2

Working on .Net Core Project and created below service to share common methods across the pages.

namespace MyApp.Tests.Services
{
    public class UserServiceTest
    {
        [Fact]
        public async Task CreateUser_ShouldCreateUser()
        {
            var user = new UserResponse
            {
                Id = "111",
                Email = "john@email.com",
                FirstName = "John",
                LastName = "Doe",
                CompanyName = "SomeCompany",
                PhoneNumber = "9123456789"
            };

            var appUser = new ApplicationUser
            {
                UserName = user.Email,
                Email = user.Email,
                FirstName = user.FirstName,
                LastName = user.LastName,
                CompanyName = user.CompanyName,
                PhoneNumber = user.PhoneNumber
            };

            var logger = Mock.Of<ILogger<UserService>>();
            var mockUserStore = new Mock<IUserStore<ApplicationUser>>();
            mockUserStore
                .Setup(x => x.CreateAsync(appUser, CancellationToken.None))
                .ReturnsAsync(IdentityResult.Success).Verifiable();

            // Tried this one as well but still getting null instead of IdentityResult
            // mockUserStore
            //     .Setup(x => x.CreateAsync(appUser, CancellationToken.None))
            //     .ReturnsAsync(new IdentityResultMock(true));

            var userManager = new UserManager<ApplicationUser>(mockUserStore.Object, null, null, null, null, null, null, null, null);
            var _userService = new UserService(userManager, logger);

            var result = await _userService.CreateUserInApp(user);

            Assert.True(result.Succeeded);
        }
    }

    public class IdentityResultMock : IdentityResult
    {
        public IdentityResultMock(bool succeeded) {
            base.Succeeded = succeeded;
         }
    }
}

Also wrote the Unit Test case for this service like below to test the UserService

namespace MyApp.Tests.Services
{
    public class UserServiceTest
    {
        [Fact]
        public async Task CreateUser_ShouldCreateUser()
        {
            var user = new UserResponse
            {
                Id = "111",
                Email = "john@email.com",
                FirstName = "John",
                LastName = "Doe",
                CompanyName = "SomeCompany",
                PhoneNumber = "9123456789"
            };

            var appUser = new ApplicationUser
            {
                UserName = user.Email,
                Email = user.Email,
                FirstName = user.FirstName,
                LastName = user.LastName,
                CompanyName = user.CompanyName,
                PhoneNumber = user.PhoneNumber
            };

            var logger = Mock.Of<ILogger<UserService>>();
            var mockUserStore = new Mock<IUserStore<ApplicationUser>>();
            mockUserStore
                .Setup(x => x.CreateAsync(appUser, CancellationToken.None))
                .ReturnsAsync(IdentityResult.Success).Verifiable(); ;

            var userManager = new UserManager<ApplicationUser>(mockUserStore.Object, null, null, null, null, null, null, null, null);
            var _userService = new UserService(userManager, logger);

            var result = await _userService.CreateUserInApp(user);

            Assert.True(result.Succeeded);
        }
    }
}

While running test in user service at

var createResult = await _userManager.CreateAsync(appUser);

createResult I am getting null due to this Test Case is failing and getting null reference exception. If I could return IdentityResult from mock CreateAsync setup then it will pass but not sure what wrong I am doing. Also Can not create object of IdentityResult because 'Succeeded' is protected and can not assign value explicitly. Please help. Thanks :)

Ravi
  • 272
  • 1
  • 14

1 Answers1

2

We need to see what is happening inside the constructor:

var userManager = new UserManager<ApplicationUser>(mockUserStore.Object, null, null, null, null, null, null, null, null);

But not really. If you are testing the UserService here, then what you should be mocking is the UserManager and not it's internal dependency IUserStore.

Why is that? Becaus the internals of the UserManager might change and then you'll have to change both the UserManager tests and the UserService tests.

Mock the create of the UserManager as you do for the IUserStore and you'll see it was some other dependency in UserStore or somewhere totally outside the scope of the unit test.

Edit 1

I think I figured out your problem:

mockUserStore
    .Setup(x => x.CreateAsync(appUser, CancellationToken.None))
    .ReturnsAsync(IdentityResult.Success).Verifiable();

And the calling with

var result = await _userService.CreateUserInApp(user);

User object and appUser object are not the same, so the mocking framework does not return the expected value.

To make sure that this is the problem, try to mock with

mockUserStore
    .Setup(x => x.CreateAsync(It.IsAny<ApplicationUser>(), It.IsAny<CancellationToken>()))
    .ReturnsAsync(IdentityResult.Success).Verifiable();
Athanasios Kataras
  • 20,791
  • 3
  • 24
  • 45
  • I can mock userManager like https://stackoverflow.com/questions/49165810/how-to-mock-usermanager-in-net-core-testing but it will not tackle main issue of returning IdentityResult. – Ravi Dec 18 '19 at 08:52
  • Check the updated answer. It might solve your problem. – Athanasios Kataras Dec 18 '19 at 10:59
  • It works :). One Request - Could you please update your answer(with updated method name as CreateUserInApp). So that I can mark it accepted answer. – Ravi Dec 18 '19 at 11:07