Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / mocking

How to Use Mocking Framework in Tests

5.00/5 (3 votes)
10 Mar 2017CPOL3 min read 6.3K  
Cases when you may, and when you should not use mocking framework

Let's consider cases, when you may, and when you should not use mocking framework. Also here, I'll show some patterns that you may want to use with mocking framework.

If You Don't Care...

Sometimes, a class you want to test (system under test, SUT) requires some dependencies. But it can happen that your tests do not actually rely on work of these dependencies. In case you are content with default values returned from all members of a dependency, you may use mocking framework to create it:

C#
var userSettingsService = new Mock<IUserSettingsService>().Object;
 
_controller = new SettingsController(userSettingsService);

But even in this case...

... Limit Usage of the Mocking Framework

Avoid situations when each test of your test class contains code, related to the mocking framework. It will make refactoring of code more difficult. Try to concentrate all such code inside test initialize and test cleanup methods.

There are times when it is not possible. For example, nearly any of your tests may require setting behaviour of some method of your dependency interface. Here you have several options:

Configuration Method

In your test class, you may create helper methods which will help with configuration of expectations:

C#
private void UserIsNotAuthenticated(Mock<IAuthenticationService> authenticationService)
{
    authenticationService.Setup(s => s.IsAuthenticated(It.IsAny<HttpRequestBase>())).Returns(false);
}

Now you can use these methods in your tests instead of using the mocking framework directly:

C#
UserIsNotAuthenticated(_authenticationService);
 
var result = (RedirectResult)_controller.Index(new LogonModel
{
    ReturnUrl = FakeUrl
});
 
Assert.AreEqual(FakeUrl, result.Url);

It will reduce impact of the mocking framework on your tests, and simplify refactoring.

Preconfigured Mocks

Configuration methods can help if you use them in one test class. But if you need to define behaviour of some method in several test classes, there is another possible approach. You can create preconfigured mocks:

C#
internal class AuthenticationServiceStub : Mock<IAuthenticationService>
{
    public AuthenticationServiceStub()
    {
        Setup(s => s.GetUserId(It.IsAny<string>())).Returns(1);
    }
 
    public void SetIsPasswordKeyValidTo(bool value)
    {
        Setup(s => s.IsPasswordKeyValid(It.IsAny<string>())).Returns(value);
    }
 
    // other code
}

In this case, you manually create class of mock, and derive it from class of the mocking framework. Here, you can encapsulate common configuration for all instances (in constructor), and also define helper methods with meaningful names to configure behaviour of separate members.

It is very simple to use such preconfigured mocks:

C#
[TestInitialize]
public void TestInitialize()
{
    _authenticationService = new AuthenticationServiceStub();
    _controller = new PasswordController(_authenticationService.Object);
}

as well as its configuration methods:

C#
_authenticationService.SetIsPasswordKeyValidTo(false);
 
var result = (ViewResult)_controller.Index(Constants.Domain, "invalidKey");
 
Assert.AreEqual("Error", result.ViewName);

Complex Behaviour of Mocks

There are cases when you want complex behaviour from your mocks. For example, you could want several methods of some interface to work together and provide consistent information. Although it is possible to achieve it using the mocking framework, I advice you to resist this temptation. Implement such mocks manually:

C#
public class PermissionsProviderStub : IPermissionsProvider
{
    internal const string NoPermissions = "NoPermissions";
    internal const string ReadPermission = "ReadPermission";
 
    public Permissions GetPermissions(string objectId, int userId)
    {
        if (objectId.Equals(NoPermissions))
            return new NoPermissions();
 
        if (objectId.Equals(ReadPermission))
            return new Permissions { HasReadAccess = true };
 
        throw new ArgumentException($"Stub does not support ObjectId: {objectId} not supported");
    }
}

It is much cleaner and easier to understand.

Nevertheless, even in this case, the mocking framework can help you...

Partial Implementation

There are interfaces with a very long list of members. I know, that in many situations, we should break up such interfaces into smaller ones. But still they exist. You may want to implement complex behaviour for couple of its members, and you don't care about the other members. In this case, you can use partial implementation of the interface:

C#
public class LanguageProviderStub : Mock<ILanguageProvider>
{
    public LanguageProviderStub()
    {
        Setup(p => p.GetPreferredLanguage(It.IsAny<int>(), 
        It.IsAny<List<int>>(), It.IsAny<int>()))
            .Returns((Func<int, List<int>, int, Lang>)GetPreferredLanguage);
 
        Setup(p => p.GetPreferredLanguageId(It.IsAny<int>(), 
        It.IsAny<List<int>>(), It.IsAny<int>()))
            .Returns((Func<int, List<int>, int, int>)GetPreferredLanguageId);
    }
 
    private Lang GetPreferredLanguage
    (int language, List<int> available, int defaultLanguage)
    {
        if (available.Contains(language))
            return new Lang(language);
 
        return new Lang(defaultLanguage);
    }
 
    private int GetPreferredLanguageId
    (int language, List<int> available, int defaultLanguage)
    {
        var lang = GetPreferredLanguage(language, available, defaultLanguage);
 
        return lang != null ? lang.LangId : -1;
    }
}

You assign your implementation to the chosen methods, and make the mocking framework take care of the rest:

C#
var controller = new LanguageController(new LanguageProviderStub().Object);

Refactoring

I want to draw your attention to the fact that using mocking framework does not mean you should not refactor the code of your tests. You may start with simple usage of the mocking framework for some interface. But later, as your tests evolve and grow, you may consider writing configuration methods and even preconfigured mocks. The way you use the mocking framework now is not written in stone, it may require changes in the future.

Conclusion

Let me summarize information in this article.

  • Choose your mocking framework wisely.
  • Use it if you are content with default values of mocked members.
  • Limit usage of the framework: use configuration methods and preconfigured mocks.
  • Implement complex behaviour manually. In some cases, partial implementation is allowed.
  • Refactoring is still mandatory.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)