Mocking - cannot instantiate proxy class of property?

13,900

Solution 1

Create a mock object of UserManager first. Then setup its virtual method FindByIdAsync(given that the type of the property UserManager is a class AppUserManager and lets say this class implements IAppUserManager).

var yourMockOfUserManager = new Mock<IAppUserManager>();
yourMockOfUserManage.Setup(x=>x.FindByIdAsync(It.IsAny<string>())).Returns(() => null);

and finally

mockOwinManager.Setup(x => x.UserManager).Returns(() => yourMockOfUserManager.Object);

Solution 2

UserManager class accepts IUserStore<ApplicationUser> in a constructor, which is used to get an access to FindByIdAsync and etc

When I need to test classes which require UserManager, I do mock for IUserStore and setup its FindByIdAsync method, then I create an instance of UserManager and provide my mock into its parameters. This is a class constructor which requires UserManager:

internal class UserManagerWrapper
{
    private readonly IEditUserResponceDataModelProvider _editUserResponceDataModelProvider;
    private readonly UserManager<User> _userManager;
    private readonly IUserModelFactory _userModelFactory;

    public UserManagerWrapper(UserManager<User> userManager,
        IUserModelFactory userModelFactory,
        IEditUserResponceDataModelProvider editUserResponceDataModelProvider)
    {
        _userManager = userManager;
        _userModelFactory = userModelFactory;
        _editUserResponceDataModelProvider = editUserResponceDataModelProvider;
    }

    public async Task<IUserModel> FindByIdAsync(string id)
    {      
        var user = await _userManager.FindByIdAsync(id);
        return _userModelFactory.Create(user.Id, user.Email, user.Year, user.UserName);
    }
}

This is my test for UserManagerWrapper:

private Mock<IUserStore<User>> UserStoreMock { get; set; }

[SetUp]
public void SetUp()
{
    UserStoreMock = new Mock<IUserStore<User>>();
    UserStoreMock.Setup(x => x.FindByIdAsync(It.IsAny<string>(), CancellationToken.None))
        .Returns(Task.FromResult(new User() {Year = 2020}));
}

[TestCase(2020)]
public async Task ValidateUserYear(int year)
{

    var userManager = new UserManager<User>(UserStoreMock.Object, null, null, null, null, null, null, null, null);

    var userManagerWrapper = new UserManagerWrapper(userManager, new UserModelFactory(), null);
    var findByIdAsync = await userManagerWrapper.FindByIdAsync("1");
    Assert.AreEqual(findByIdAsync.Year, year);
}`:
Share:
13,900
Evangelos Aktoudianakis
Author by

Evangelos Aktoudianakis

Updated on June 04, 2022

Comments

  • Evangelos Aktoudianakis
    Evangelos Aktoudianakis almost 2 years

    Inside my tests, here is my code:

    [SetUp]
    public void Initialise()
    {
        mockOwinManager = new Mock<IOwinManager<ApplicationUser, ApplicationRole>>();
        mockSearch = new Mock<ISearch<ApplicationUser>>();
        mockMail = new Mock<IRpdbMail>();
        mockUserStore = new Mock<IUserStore<ApplicationUser>>();
    
        mockOwinManager.Setup(x => x.UserManager).Returns(() => new AppUserManager(mockUserStore.Object));
    
        sut = new UsersController(mockOwinManager.Object, mockSearch.Object, mockMail.Object);
    }
    

    And then the test itself:

    [Test]
    public void WhenPut_IfUserIsNullReturnInternalServerError()
    {
        //Arrange
        mockOwinManager.Setup(x => x.UserManager.FindByIdAsync(It.IsAny<string>())).Returns(() => null);
    
        //Act
        var response = sut.Put(new AppPersonUpdate());
    
        //Assert
        Assert.AreEqual(response.Result.StatusCode, HttpStatusCode.InternalServerError);
    }
    

    But my arrange line throws the following error:

    Can not instantiate proxy of class: Microsoft.AspNet.Identity.UserManager`1[[SWDB.BusinessLayer.Identity.ApplicationUser, SWDB.BusinessLayer, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]. Could not find a parameterless constructor.

    Why is this so, since in Setup I've set my mockOwinManager's UserManager property in what I'd like it to return already?

  • Evangelos Aktoudianakis
    Evangelos Aktoudianakis over 8 years
    problem is this class doesn't implement any interface...Not that I know of. I've tried your solution without interfaces, and it still gives me the same error. It's as if it refuses to return the instantiated property I am passing to it.
  • Afaq
    Afaq over 8 years
    Oh, I see. If UserManager is a property then did you try mockOwinManager.SetupGet(x=>x.UserManager).... .?
  • Afaq
    Afaq over 8 years
    Does the class AppUserManager contain a public constructor without any arguments ? Try not setting up UserManager property and directly do mockOwinManager.Setup(x => x.UserManager.FindByIdAsync(It.IsAny<string>())).Returns(() => null);
  • Evangelos Aktoudianakis
    Evangelos Aktoudianakis over 8 years
    Your answer has guided me to the answer (by 80%) . It looks like each step in the call chain needs to be mocked somehow instead of it all being set up on root level. I can't say I understand why though :(