3

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"); } 
2
  • There was no setup on the mock so any members called will be null. secondly, you make a fake manager and then mock the fake manager. Feels like an XY problem and lastly you should not be testing code you do not control. Sounds like you have tight coupling to implementation concerns. Commented Jun 16, 2018 at 16:01
  • I understand your point. I am not that familiar with unit testing in .NET. I added the setup on my mockUserManager , but it stills returns null Commented Jun 16, 2018 at 17:07

1 Answer 1

5

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 = "[email protected]" }; 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); } 
Sign up to request clarification or add additional context in comments.

1 Comment

I agree with this approach. Just like @Nkosi mentioned, mocking the entirety of the UserManager is usually not necessary, though there may be times where a dependency is taken on the UserManager and the basic UserStore functionality is needed within the object you're actually testing. This is a good mixture to get the job done.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.