简体   繁体   中英

How to mock UserManager in .NET Core with NUnit?

I'd like to unit test my application made in .NET Core with Razor Pages. I need to mock my dbContext and my UserManager - however, I seem to keep getting null back as result.

FakeUserManager

public class FakeUserManager : UserManager<ApplicationUser>
{
  public FakeUserManager()        
      : base(new Mock<IUserStore<ApplicationUser>>().Object,
         new Mock<IOptions<IdentityOptions>>().Object,
         new Mock<IPasswordHasher<ApplicationUser>>().Object,
         new IUserValidator<ApplicationUser>[0],
         new IPasswordValidator<ApplicationUser>[0],
         new Mock<ILookupNormalizer>().Object,
         new Mock<IdentityErrorDescriber>().Object,
         new Mock<IServiceProvider>().Object,
         new Mock<ILogger<UserManager<ApplicationUser>>>().Object)
    { }
}

My TestClass

 [TestFixture]
 public class UserTest
 {
     private ApplicationDbContext _dbContext { get; set; }
     public void TestSetUp()
     {
         DbContextOptionsBuilder<ApplicationDbContext> optionsbuilder = new DbContextOptionsBuilder<ApplicationDbContext>();
         optionsbuilder.UseInMemoryDatabase(databaseName: "TestDB");
         _dbContext = new ApplicationDbContext(optionsbuilder.Options);
         _dbContext.Users.Add(new ApplicationUser
         {
             Id = "1",
             FirstName = "Test",
             LastName = "Alpha",
             CreatedAt = DateTime.Now,
             UpdatedAt = DateTime.Now,
         });
         _dbContext.SaveChanges();
     }

     [Test]
     public void MyTest()
     {
         Mock<FakeUserManager> fakeUserManager = new Mock<FakeUserManager>();
         var result = fakeUserManager.Object.FindByIdAsync("1");

         // I know this Assert always returns  success, but I'd like var result to return my ApplicationUser found by the FakeUserManager
         Assert.AreEqual("test", "test");
     }
 }

Before marking this question as duplicate, yes - I'd look at other posts but they did not satisfy my answer.

When I run this test, var result returns null and I do not understand why.

edit ###

    [Test]
    public async void MyTest() 
    {
        var mockStore = Mock.Of<IUserStore<ApplicationUser>>();
        var mockUserManager = new Mock<UserManager<ApplicationUser>>(mockStore, null, null, null, null, null, null, null, null);

        var user = new ApplicationUser
        {
            Id = "1",
            FirstName = "Test",
            LastName = "Test"
        };

        mockUserManager
            .Setup(x => x.CreateAsync(It.IsAny<ApplicationUser>(), It.IsAny<string>()))
            .ReturnsAsync(IdentityResult.Success);

        await mockUserManager.Object.CreateAsync(user);

        var result = mockUserManager.Object.FindByIdAsync("UserA");

        Assert.AreEqual("test", "test");


    }

You should not test whether or not the UserManager can retrieve data from the DB (that's an internal concern for the framework beyond your scope). Instead you should mock the functionality for FindByIdAsync for the UserManager like so:

var UserStoreMock = Mock.Of<IUserStore<AppUser>>();
var userMgr = new Mock<UserManager<AppUser>>(UserStoreMock, null, null, null, null, null, null, null, null);
var user = new AppUser() { Id = "f00", UserName = "f00", Email = "f00@example.com" };
var tcs = new TaskCompletionSource<AppUser>();
tcs.SetResult(user);
userMgr.Setup(x => x.FindByIdAsync("f00")).Returns(tcs.Task);

For your identity setup to ensure an authenticated user with proper rights is making the call:

Mock<ClaimsPrincipal> ClaimsPrincipalMock = new Mock<ClaimsPrincipal>();
ClaimsPrincipalMock.Setup(x => x.IsInRole("Admin")).Returns(true);
ClaimsPrincipalMock.Name = "SomeAdmin";
ClaimsPrincipalMock.SetupGet(x => x.Identity.Name).Returns(ClaimsPrincipalMock.Name);

Then for your account controller set the context up like so, passing your UserManager as one of the DI arguments:

AccountController SUT = new AccountController(userMgr);
var context = new ControllerContext();
context.HttpContext = new DefaultHttpContext();
context.HttpContext.User = ClaimsPrincipalMock.Object;
SUT.ControllerContext = context;

Finally in your controller the matching code would be something like:

[HttpGet("User")]
public async Task<IActionResult> GetUser(string id)
{
    var user = await _userManager.FindByIdAsync(id);     
    bool isAdmin= User.IsInRole("Admin");

    if (user == default(AppUser) || (User.Identity.Name != user.UserName && isAdmin == false))
    {
         return NotFound();
    }

    return Ok(user);
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM