DotNetT2 Light_1200x303

Are you looking for a solution to speed up your unit test development? Or perhaps you want to write more stable and reliable unit tests? Or you simply want the unit tests to be isolated from their environment? Then you need JustMock.

The following items will be covered to help you write better tests:

  1. Why Mocking – how mock objects help you
  2. Real World Example – an example of code to be tested
  3. Testing the Example – how to use mocking to test the example
  4. AAA Pattern – a pattern emerges when writing clean tests

Why Mocking?

Mocking is a process used in unit testing where the unit being tested has external dependencies. The purpose of mocking is to isolate and focus on the code being tested and not in handling the behavior or state of external dependencies like database or service that could also break your test. In mocking, the dependencies are replaced by closely controlled replacement objects, such as a mock object, that simulate the behavior of the real ones.

The mock object is not simply an object with hard coded values to return. The mock object also acts as a collaborator and is subject to dynamic behavioral modification and verification. Such a collaborator will help you achieve your desired unit-testing goal for a given system and a controlled set of inputs. This is achieved by having the mock object stand-in for the real object and return data or execute a behavior you have specified.

WhatIsMock

To get a complete overview of mocks, an informative article named “Mocks aren’t stubs” by Martin Fowler is a must read.

http://martinfowler.com/articles/mocksArentStubs.html

After you are finished, it’s time to give you a good grasp of mocking with a real world example.

Real World Example

I am going to implement part of a banking system. This includes the transfer of funds between two different currency accounts using the currency converter service.

To begin, I have created an ICurrencyService interface:

public interface ICurrencyService
{
    decimal GetConversionRate(string fromCurrency, string toCurrency);
}

This service interface will be injected to an AccountsService class that is responsible for the transfer funds operation. Once the source and destination account objects are passed to the operation, it will then withdraw from source, convert the currency based on current rate, and finally deposit the converted amount to the target account. There will be a check for available balance, authorization, approval, etc. in more complex scenarios, but they are out of scope for this article.

public class AccountService : IAccountService
{
    private readonly ICurrencyService currencyService;
  
    public AccountService(ICurrencyService currencyService)
    {
        this.currencyService = currencyService;
    }
  
    public void TransferFunds(Account from, Account to, decimal amount)
    {
        from.Withdraw(amount);
        decimal conversionRate = currencyService.GetConversionRate(from.Currency, to.Currency);
        decimal convertedAmount = amount * conversionRate;
        to.Deposit(convertedAmount);
    }
}

Testing the Example

The goal is to validate or assert the transfer funds operation between two accounts. Therefore, this is the system under test (SUT), and the currency service is the collaborator which will be mocked. I am using JustMock for this purpose, but the core concept is the same with other mocking tools.

Arrange

First I will create the mock of the ICurrenyService interface:

ICurrencyService currencyService = Mock.Create<ICurrencyService>();

From the account service implementation, I can see that GetCurrencyService is being called to retrieve the conversation rate. The next step is to set an expected return value for it.

Mock.Arrange(() => currencyService.GetConversionRate("GBP", "CAD"))
.Returns(2.20m).MustBeCalled();

Mock.Arrange is the entry-point for setting expected behavior for a given mock. This line is self-explanatory, but I did use one extra option: MustBeCalled. This ensures that if currencyService.GetConversationRate is not called with the above criteria, then it will fail the test.

Since I have finished setting the behavior, I will then create an instance of the AccountService class followed by the source and destination Account classes.

var accountService = new AccountService(currencyService);
  
var canadianAccount = new Account(0, "CAD");
var britishAccount = new Account(0, "GBP");

Act

Next, I will add some money into the GBP account:

britishAccount.Deposit(100);

Then transfer it to my Canadian account:

accountService.TransferFunds(britishAccount, canadianAccount, 100);

Assert

Once the transfer is complete, I need to make sure the operations happened as expected. I will first assert the balance of the two accounts:

Assert.AreEqual(0, britishAccount.Balance);
Assert.AreEqual(220, canadianAccount.Balance);

Then I will assert the mock to verify whether the required GetConversationRate method is called as expected:

Mock.Assert(currencyService);

And here is what the whole test looks like:

[TestMethod]
public void TestTransferFunds()
{
    // Arrange
    ICurrencyService currencyService = Mock.Create<ICurrencyService>();
    Mock.Arrange(() => currencyService.GetConversionRate("GBP", "CAD"))
       .Returns(2.20m).MustBeCalled();
 
    var accountService = new AccountService(currencyService);
    var canadianAccount = new Account(0, "CAD");
    var britishAccount = new Account(0, "GBP");
 
    // Act
    britishAccount.Deposit(100);
    accountService.TransferFunds(britishAccount, canadianAccount, 100);
 
    // Assert
    Assert.AreEqual(0, britishAccount.Balance);
    Assert.AreEqual(220, canadianAccount.Balance);
    Mock.Assert(currencyService);
}

AAA Pattern

You may have noticed that there were three easy steps involved with the unit test. This is part of a well-known pattern called Arrange – Act – Assert or AAA. JustMock’s syntax is implemented to strictly follow the AAA pattern to give you a well-structured flow, even in the most complex scenarios.

In this post, I described how mocking will help you. I then built an example project and test to illustrate how to proceed. Mocking helps you write clean unit tests, and it enables you to focus on the test logic by isolating external factors. With mocking, unit testing is no longer a chore.

This post was originally published in 2012 by Mehfuz Hossain and has been revised for accuracy and completeness.

JustMock-forum-02-2012


Mihail Vladov
About the Author

Mihail Vladov

Mihail Vladov is a Software Engineering Manager at Progress. He has more than a decade of experience with software and product development and is passionate about good software design and quality code. Mihail helped develop the WPF controls suite and Document Processing libraries which are used by thousands of developers. Currently, he is leading the JustMock team. In his free time, he loves to travel and taste different foods. You can find Mihail on LinkedIn.

Related Posts

Comments

Comments are disabled in preview mode.