XUnit Mocking Custom Identity Managers and Stores, Can not instantiate proxy of class: API.Identity.Managers.MyUserManager

Viewed 160

I'm using Moq for mocking my AuthenticationController, the error happens when initializing the XUnit test, The problem lies in the constructor of the test class on line:

 _myUserManager = new Mock<MyUserManager<AppUser>>(_myUserStore.Object);

On this line an exception of type Castle.DynamicProxy.InvalidProxyConstructorArgumentsException, when trying to mock the object.

and the messege and stacktrace is here:

Message: 
Castle.DynamicProxy.InvalidProxyConstructorArgumentsException : Can not instantiate proxy of class: API.Identity.Managers.MyUserManager`1[[API.Identity.Models.AppUser, API, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]].
Could not find a constructor that would match given arguments:
Castle.Proxies.IMyUserStoreProxy

Stack Trace: 
ProxyGenerator.CreateClassProxyInstance(Type proxyType, List`1 proxyArguments, Type classToProxy, Object[] constructorArguments)
ProxyGenerator.CreateClassProxy(Type classToProxy, Type[] additionalInterfacesToProxy, ProxyGenerationOptions options, Object[] constructorArguments, IInterceptor[] interceptors)
CastleProxyFactory.CreateProxy(Type mockType, IInterceptor interceptor, Type[] interfaces, Object[] arguments)
Mock`1.InitializeInstance()
Mock`1.OnGetObject()
Mock.get_Object()
Mock`1.get_Object()
AuthenticateControllerTests.ctor() line 47

here is the test class

public class AuthenticateControllerTests {

    private AuthenticateController _controller;

    private Mock<ILoggerSevice> _loggerSevice;
    private Mock<IJwtAuthService> _jwtAuthService;
    private Mock<IEmailService> _emailService;
    private Mock<IEmailGateway> _emailGateway;
    private Mock<IValidationHelper> _validationHelper;

    private Mock<IMyUserStore> _myUserStore;
    private Mock<MyUserManager<AppUser>> _myUserManager;
    private Mock<IMyCustomerUserStore> _myCustomerUserStore;
    private Mock<MyCustomerUserManager<AppCustomerUser>> _myUserCustomerManager;

    private Mock<SignInManager<AppUser>> _signInManager;
    private Mock<SignInManager<AppCustomerUser>> _signInCustomerManager;

    public AuthenticateControllerTests() {
        //set up authenticate controller
        _loggerSevice = new Mock<ILoggerSevice>();
        _jwtAuthService = new Mock<IJwtAuthService>();
        _emailService = new Mock<IEmailService>();
        _emailGateway = new Mock<IEmailGateway>();
        _validationHelper = new Mock<IValidationHelper>();


        _myUserStore = new Mock<IMyUserStore>();
        _myUserManager = new Mock<MyUserManager<AppUser>>(_myUserStore.Object);
        _signInManager = new Mock<SignInManager<AppUser>>(_myUserManager.Object);

        _myCustomerUserStore = new Mock<IMyCustomerUserStore>();
        _myUserCustomerManager = new Mock<MyCustomerUserManager<AppCustomerUser>>(_myCustomerUserStore.Object);
        _signInCustomerManager = new Mock<SignInManager<AppCustomerUser>>(_myUserCustomerManager.Object);

        _controller = new AuthenticateController(_loggerSevice.Object,
                                                _jwtAuthService.Object,
                                                _myUserManager.Object,
                                                _myUserCustomerManager.Object,
                                                _signInManager.Object,
                                                _signInCustomerManager.Object,
                                                _emailService.Object,
                                                _validationHelper.Object,
                                                _emailGateway.Object);
    }

My custom UserManager constructor look like this:

    public MyUserManager(IMyUserStore myUserStore, 
                         IOptions<IdentityOptions> optionsAccessor, 
                         IPasswordHasher<AppUser> passwordHasher, 
                         IEnumerable<IUserValidator<AppUser>> userValidators, 
                         IEnumerable<IPasswordValidator<AppUser>> passwordValidators, 
                         ILookupNormalizer keyNormalizer, 
                         IdentityErrorDescriber errors,
                         IServiceProvider services, 
                         ILogger<UserManager<AppUser>> logger) : 
                    base(myUserStore, optionsAccessor,
                         passwordHasher, userValidators, passwordValidators,
                         keyNormalizer, 
                         errors, services, logger) {

        _myUserStore = myUserStore;
    }

Custom user store :

public interface IMyUserStore : IUserStore<AppUser>, IUserEmailStore<AppUser>, 
                                IUserPhoneNumberStore<AppUser>,
                                IUserTwoFactorStore<AppUser>, IUserPasswordStore<AppUser>, 
                                IUserRoleStore<AppUser> {

public class MyUserStore : IMyUserStore {

    private readonly IUserGateway _userGateway;
    private readonly IRoleGateway _roleGateway;
1 Answers

When mocking an implementation such as MyUserManager, Moq needs an accessible constructor to create the mock and you need to provide the arguments for said constructor.

So your constructor is

 public MyUserManager(IMyUserStore myUserStore, 
                         IOptions<IdentityOptions> optionsAccessor, 
                         IPasswordHasher<AppUser> passwordHasher, 
                         IEnumerable<IUserValidator<AppUser>> userValidators, 
                         IEnumerable<IPasswordValidator<AppUser>> passwordValidators, 
                         ILookupNormalizer keyNormalizer, 
                         IdentityErrorDescriber errors,
                         IServiceProvider services, 
                         ILogger<UserManager<AppUser>> logger)

but you're only providing an IMyUserStore argument:

new Mock<MyUserManager<AppUser>>(_myUserStore.Object);

You'll need to provide the rest of the arguments; or use a different constructor (and again provide arguments for); or better still if you can define a interface for MyUserManager, mock that instead.

Related