Kevin Amorim
Kevin Amorim

Reputation: 535

ASP.NET MVC 5 - Unit Testing Service that uses only Identity

I have this class, that, actually, only does operations on top of ASP.NET Identity.

 public class AuthenticationService : IAuthenticationService
    {
        private readonly ApplicationSignInManager _signInManager;
        private readonly ApplicationUserManager _userManager;
        private readonly IAuthenticationManager _authManager;
        private readonly HttpContextBase _context;

        public AuthenticationService(
            ApplicationSignInManager signInManager, 
            ApplicationUserManager userManager, 
            IAuthenticationManager authManager,
            HttpContextBase context)
        {
            _signInManager = signInManager;
            _userManager = userManager;
            _authManager = authManager;
            _context = context;
        }

        public async Task<SignInStatus> SignIn(string email, string password)
        {
            var result = await _signInManager.PasswordSignInAsync(email, password, true, shouldLockout: false);
            return result;
        }

        public async Task<IdentityResult> Register(string email, string password)
        {
            var user = new AppUser
            {
                UserName = email,
                Email = email,
            };

            var result = await _userManager.CreateAsync(user, password);

            return result;
        }

        public void SignOut()
        {
            _authManager.SignOut(DefaultAuthenticationTypes.ApplicationCookie);
        }

        public async Task<IdentityResult> ForgotPassword(string email, string newPassword)
        {
            var user = await _userManager.FindByEmailAsync(email);
            string resetToken = await _userManager.GeneratePasswordResetTokenAsync(user.Id);
            var result = await _userManager.ResetPasswordAsync(user.Id, resetToken, newPassword);

            return result;
        }

        public async Task<AppUser> GetUserByEmail(string email)
        {
            var user = await _userManager.FindByEmailAsync(email);
            return user;
        }

        public string GetLoggedInUserId()
        {
            if(_context.User.Identity.IsAuthenticated)
            {
                return _context.User.Identity.GetUserId();
            }
            return string.Empty;
        }
    }

I don't know if I'm injecting the right dependencies. But my question is:

In a class like this one, what would make sense to unit test? Since most methods call methods related to Identity and only return the result.

The only test that it seems right to do is what happens when I try to get the ID of a user if no user is authenticated.

Upvotes: 1

Views: 148

Answers (1)

cassandrad
cassandrad

Reputation: 3526

In almost any class you can test, assuming that it's a unit test of one entity under test and all internal dependencies(like ApplicationUserManager or IAuthenticationManager) are mocked:

  1. All internal services are called exact number of times
  2. The entity under test does not change arguments passed in a method, and correctly passes them into calls of internal services (like ApplicationUserManager or IAuthenticationManager)

So, for example, you can test in SignIn that _signInManager.PasswordSignInAsync gets called exactly once and arguments are, for email and password — the same as they were passed into SignIn; for the third unnamed argument and shouldLockout — they are according to business logic — true and false.

ForgotPassword is trickier: you have data passed from _userManager.FindByEmailAsync to _userManager.GeneratePasswordResetTokenAsync and then to _userManager.ResetPasswordAsync.
In this case, you don't need to test results of these three calls are correct as such thing should be tested in tests for _userManager, but you will need to test that calls to all these services are made exact number of times.

Upvotes: 1

Related Questions