kuzzanagi
kuzzanagi

Reputation: 55

How to unit test a class using moq that has dependencies within a method?

I want to unit test a class AuthClient (using Moq) which authenticates a user.

Problem is that my AuthenticationService dependency is not injected in the class. And I am a bit confused at how I would test the flow without injecting the dependencies.

[TestClass] 
public class AuthClient 
{
    string Dictionary<string, IList<UserPermissions> _userPermissions;

    User Login(string username, string password)
    {
        IAuthenticationService authenticationService = new AuthenticationService();
        User user = authService.Login(username, password);

        IAuthorizationService authorizationService = new AuthorizationService();
        var permissions = authorizationService.GetPermissions(user);
        _userPermissions.Add(user.Username, permissions);

        return user;
    }
}

My current unit testing code looks like:

public class UnitTestClass
{
    public string UserName {get;set;}
    public string Password {get;set;}

    [TestInitialize]
    public void Setup() 
    {
        UserName = "test";
        Password = "test123";
    }

    [TestMethod]
    public void When_ValidUserCredentials_Expect_UserIsNotNull()
    {
        var mockAuthenticationService = new Mock<IAuthenticateService>();
        mockAuthenticationService.Setup(m => m.Login(ValidUserName, ValidPassword)).Returns(ValidUserDto);

        var mockAuthorizationService = new Mock<IAuthorizeService>();
        mockAuthorizationService.Setup(m => m.GetAllPermissions(ValidUserId)).Returns(ValidPermissionList);

        var authClient = new Mock<AuthClient>();
        // I want to use mock dependencies here to test flow against mock data
        User user = authClient.Login(UserName, Password); 

        Assert.IsNotNull(user);
    }
}

Any ideas where everything went wrong?

Upvotes: 2

Views: 12644

Answers (1)

ry8806
ry8806

Reputation: 2348

Moq allows you to test classes that depend on other classes/object (among many other things). Note: Moq is not an IOC container.

In your AuthClient class you are not allowing it to be given any dependencies, instead it is instantiating its own e.g.

IAuthenticationService authenticationService = new AuthenticationService();

Instead you need to define a constructor on the AuthClient class which accepts two objects (on which it should depend), there are other ways to "inject" dependencies, but for now we'll use Constructor Injection (good example)

For example

public class AuthClient 
{
    string Dictionary<string, IList<UserPermissions> _userPermissions;
    private IAuthenticationService _authenticationService;
    private IAuthorizationService _authorizationService;

    public AuthClient(IAuthenticationService authenticationService, IAuthorizationService authorizationService)
    {
        _authenticationService = authenticationService;
        _authorizationService = authorizationService;
    }

    User Login(string username, string password)
    {
        User user = _authenticationService.Login(username, password);

        var permissions = _authorizationService.GetPermissions(user);
        _userPermissions.Add(user.Username, permissions);

        return user;
    }
}

Now, everytime you want to use this class you have to tell it which Authorization Service and Authentication Service it should use. You've de-coupled your AuthClient from a specific implementation - now its very testable and reusable (if you wanted to create a new AuthenticationService which does something totally different to the old one, you only have to write a class which Implements IAuthenticationService!)

You must now include AuthClient's dependencies (give it to its constructor) everytime you want to use it. You should read up more on Dependency Injection and IOC (inversion of control) (it is a very large topic with a lot of different ways to do the same kinds of things), google is your friend here.

The test class should now look like this:

public class UnitTestClass
{
    public string UserName {get;set;}
    public string Password {get;set;}

    [TestInitialize]
    public void Setup() 
    {
        UserName = "test";
        Password = "test123";
    }

    [TestMethod]
    public void When_ValidUserCredentials_Expect_UserIsNotNull()
    {
        var mockAuthenticationService = new Mock<IAuthenticateService>();
        mockAuthenticationService.Setup(m => m.Login(ValidUserName, ValidPassword)).Returns(ValidUserDto);

        var mockAuthorizationService = new Mock<IAuthorizeService>();
        mockAuthorizationService.Setup(m => m.GetAllPermissions(ValidUserId)).Returns(ValidPermissionList);

        // Here we are "injecting" the dependencies into the AuthClient
        var authClient = new AuthClient(mockAuthenticationService.Object, mockAuthorizationService.Object);
        // This service call will now use the supplied (mocked) services above
        User user = authClient.Login(UserName, Password); 

        Assert.IsNotNull(user);
    }
}

Upvotes: 10

Related Questions