Unit Testing in a Test Driven Manner:

In a previous post [https://heraclitusonsoftware.wordpress.com/2008/12/16/endo-testing-discussion/], I wrote a response to a post from Dan North around the subject of endo-testing and unit testing using Mockito/JMock.

In this post I want to illustrate reasons why I have chosen to switch to Mockito as my ‘mocking’ tool of choice. To help me do this I am going to use the example of an Order and a Warehouse taken from [1].

Description of Problem

We want to take an order object and fill it from a warehouse object. The order is very simple, with only one product and a quantity. The warehouse holds inventories of different products. When we ask an order to fill itself from a warehouse there are two possible responses. If there’s enough product in the warehouse to fill the order, the order becomes filled and the warehouse’s amount of the product is reduced by the appropriate amount. If there isn’t enough product in the warehouse then the order isn’t filled and nothing happens in the warehouse.

Creating a Unit Test in a TDD manner

I add the first test to verify expected behaviour of filling an order from a warehouse. Thus I need to represent an Order and a Warehouse.

package com.heraclitus.tddexample;

import org.junit.Test;

/**
 * I test {@link Order}.
 */
public class OrderTest {

    // system-under-test
    private Order order;

    // depended-on-component
    private Warehouse warehouse;

    @Test
    public void shouldFillOrderWithWarehouse() {

        // exercise test
        order.fill(warehouse);

    }

}

Above is my shell of test so far based on the description of the problem at hand. Order is the SUT, Warehouse a known depended-on-component and the method fill a required behaviour of Order. At his point, the act of writing the test shell is still a design activity. If Order and Warehouse don’t exist within the application domain, I create them (in an abstract way so I choose as an Interface) and if the method fill doesn’t exist I add this behaviour to the Order interface.

Trying to execute as is will result in a null pointer so I must setup the test to use a real instance of an Order.

@Test
public void shouldFillOrderWhenEnoughAvailableInWarehouse() {

        // setup
        final int requiredAmount = 50;
        final String productName = "product1";

        final Order order = new OrderImpl(productName, requiredAmount);

        // exercise test
        order.fill(warehouse);

        // state verification
        assertTrue("order is showing as not filled when it should be filled.",
                order.isFilled());
}

Above, I have renamed the name of the test to be something more meaningful, added the setup which has forced me to create an implementation of the SUT (if it didn’t already exist). Added some state-based verification at the end to ensure that the state of Order has been changed to Filled after exercising the behaviour we are adding. Running the test of course fails cause we still yet haven’t implemented fill.

An implementation of Order:

public class OrderImpl implements Order {

    private final String productName;
    private final int requiredAmount;
    private boolean filled = false;

    public OrderImpl(final String productName, final int requiredAmount) {
        this.productName = productName;
        this.requiredAmount = requiredAmount;
    }

    public void fill(final Warehouse warehouse) {
       filled = warehouse.removeFromInventoryIfAvailable(requiredAmount,
                productName);
    }

    public boolean isFilled() {
        return filled;
    }

}

I implement the fill behaviour to use the depended-on-component Warehouse. Doing so causes me to discover a new behaviour needed on Warehouse.

Note: Often in TDD examples, you see people enter a constant here, in this case hard coding the state of filled to be true within the fill method. Then writing another test where this code can no longer satisfy and requiring them to rewrite a better implementation, in this case I am using what I perceive to be an obvious implementation by delegating the responsibility of removing inventory to the Warehouse type and getting it to return state indicating success/failure.

Returning to my test and executing it, it fails as of yet I have initialized my depended-on-component that is crucial to the actual implementation and the test. It is at this point that we become interested in the differing techniques used along with TDD in unit tests.

Classical TDD

In [1], Fowler distinguishes between Classical and Mockist TDD’ers. If I were a classical TDD’er they I would use the actual implementation of Warehouse within the unit test.

Example:

@Test
public void shouldFillOrderWhenEnoughAvailableInWarehouse() {

        // setup
        final int requiredAmount = 50;
        final String productName = "product1";

        order = new OrderImpl(productName, requiredAmount);

        warehouse = new WarehouseImpl();
        warehouse.addInventory(200, "product1");

        // exercise test
        order.fill(warehouse);

        // state verification
        assertTrue("order is showing as not filled when it should be filled.",
                order.isFilled());
    }

Using the classical approach, we use the actual implementation and set its state up in a way that will force out test down the path we wish to check. For this test to pass now we require:

  1. The actual implementation of Warehouse and newly discovered behaviour must be implemented sufficiently to allow the test to pass
  2. If the depended-on-component also requires that other components be set up for it to work, the setup for this test ends up starting to grow and become more complex

Taking the case that in fact the true implementation of Warehouse does use at least one other component which is required to be setup, we may opt to use a Test Double to avoid adding complexity to the test and keep its setup simple (hopefully).

Mockist TDD

A mockist approach to TDD (as far as I understand) is when we opt to use a Test Double to represent the depended-on-component in place of the actual implementation. I use the term test double (taken from [2]) to emphasize that this test double does not have to be a mock but can be one of the other members of the test double taxonomy (stub etc)

Mockist TDD: Hand Rolled Test Stub Example

In this example we write our own test stub implementation of a Warehouse:

/**
 * Configurable Test Stub implementation of {@link Warehouse} that uses a
 * {@link HashMap} to store its inventory state and makes no use of any
 * collaborators/depended-on-components.
 */
public class WarehouseConfigurableTestStub implements Warehouse {

    private final Map inventoryStore = new HashMap();

    public Integer getInventoryCount(final String productName) {
        if (inventoryStore.containsKey(productName)) {
            return inventoryStore.get(productName).intValue();
        }
        return Integer.valueOf(-1);
    }

    public void addInventory(final int numOfItems, final String productName) {
        if (inventoryStore.containsKey(productName)) {
            final int currentInventoryCount = inventoryStore.get(productName)
                    .intValue();
            inventoryStore.put(productName, currentInventoryCount + numOfItems);
        } else {
            inventoryStore.put(productName, numOfItems);
        }
    }

    public boolean removeFromInventoryIfAvailable(final int requiredAmount,
            final String productName) {
        if (inventoryStore.containsKey(productName)
                && inventoryStore.get(productName).intValue() >= requiredAmount) {
            decreaseInventory(requiredAmount, productName);
            return true;
        }
        return false;
    }

    private void decreaseInventory(final int numItems, final String productName) {
        if (inventoryStore.containsKey(productName)) {
            final int currentInventoryCount = inventoryStore.get(productName)
                    .intValue();
            inventoryStore.put(productName, currentInventoryCount - numItems);
        } else {
            throw new IllegalStateException(
                    "produce does not exist to decrease");
        }
    }
}

with the test looking like so:

@Test
public void shouldFillOrderWhenEnoughAvailableInWarehouse() {

        // setup
        final int requiredAmount = 50;
        final String productName = "product1";

        order = new OrderImpl(productName, requiredAmount);

        warehouse = new WarehouseConfigurableTestStub();
        warehouse.addInventory(200, "product1");

        // exercise test
        order.fill(warehouse);

        // state verification
        assertTrue("order is showing as not filled when it should be filled.",
                order.isFilled());
    }

While this approach solves our problems of using the real implementation of Warehouse (which required too much setup to use), we now have the problem of having to maintain this extra test code. The test code of any reasonably complex system would grow quite large in relation to our production code. Because of this, a lot of people prefer to use ‘mocking’ frameworks that allow them to create an instance that emulates the depended-on-component required for the test.

Mockist TDD: JMock Stub Example

Using a tool such as JMock we can remove the need for creating our own hand rolled stubs. Our test would look as follows:

    // mockery
    private final Mockery mockery = new JUnit4Mockery();

    @Test
    public void shouldFillOrderWhenEnoughAvailableInWarehouseAndReduceWarehouseInventory() {

        // setup
        final int requiredAmount = 50;
        final String productName = "product1";

        order = new OrderImpl(productName, requiredAmount);

        warehouse = mockery.mock(Warehouse.class);

        // stubbing (to force down path for happy path test)
        mockery.checking(new Expectations() {
            {
                allowing(warehouse).removeFromInventoryIfAvailable(
                        requiredAmount, productName);
                will(returnValue(true));
            }
        });

        // exercise test
        order.fill(warehouse);

        // state verification
        assertTrue("order is showing as not filled when it should be filled.",
                order.isFilled());
}

JMock now reduces the amount of test code we need and allows us to ‘Stub’ the removeFromInventoryIfAvailable method of Warehouse to force it to return true allowing us to test the happy path of the fill behaviour quiet easily.

Mockist TDD: Mockito Stub Example

Mockito is another tool that allows us to avoid creating hand rolled mocks. Our test would look as follows:

@Test
public void shouldFillOrderWhenEnoughAvailableInWarehouse() {

        // setup
        final int requiredAmount = 50;
        final String productName = "product1";

        order = new OrderImpl(productName, requiredAmount);

        warehouse = mock(Warehouse.class, "warehouseStub");

        // stubbing
        stub(warehouse.removeFromInventoryIfAvailable(requiredAmount,productName))
        .toReturn(true);

        // exercise test
        order.fill(warehouse);

        // state verification
        assertTrue("order is showing as not filled when it should be filled.",
                order.isFilled());
}

I believe that this shows that Mockito provides a slightly cleaner example of ‘stubbing’ than JMock as it has less boilerplate code. It also reads better. From the Mockito syntax, its clear I am using warehouse as a ‘stub’ and the comment above it could go, however on the JMock code, I prefer to leave it as the JMock code uses terms such as checking, expectations and allowing; none of which may allude to the fact that I am trying to stub the method unless you were familiar with the tool.

The test shown explaining the classical and mockist approaches to TDD were all examples of tests that fall under the category of state-based tests. An Order was a good example of when to use a state-based test as it did have state that was affected by its fill behaviour and at the end of the test we added assertions about the state of the system-under-test (Order) that will either pass or fail the test (no in-between).

Their are times when it is not the state of the SUT we care about but the interaction of the SUT with a depended-on-component. This style of test is known as an interaction-based test. We typically use a mock or a test spy as a test double for the depended-on-component to carry out interaction-based tests. As an example we write a unit test for WarehouseImpl.

Interaction-Based Test: JMock Example

/**
 * I test {@link WarehouseImpl}
 */
@RunWith(JMock.class)
public class WarehouseImplTest {

    // system under test (SUT)
    private Warehouse warehouse;

    // depended-on-components
    private InventoryService inventoryService;

    private final Mockery mockery = new JUnit4Mockery();

    @Test
    public void shouldRemoveInventoryWhenContainsEnoughStockOfProduct() {

        // setup
        inventoryService = mockery.mock(InventoryService.class);
        warehouse = new WarehouseImpl(inventoryService);

        final int requiredAmount = 50;
        final String productName = "fakeProduct";

        // behaviour verification
        mockery.checking(new Expectations() {
            {
                one(inventoryService).containsEnoughStock(requiredAmount,
                        productName);
                will(returnValue(true));

                one(inventoryService).removeFromInventoryStock(requiredAmount,
                        productName);
            }
        });

        // exercise test
        warehouse.removeFromInventoryIfAvailable(requiredAmount, productName);
    }
}

Things to note:

  1. There are no assertions at all in this test. It is a purely concerned with the interaction of the SUT with the InventoryService component.
  2. Using JMock, we use expectations about what will happen
  3. When the test runs, the test will fail fast if a method that is not expected on the inventoryService mock is invoked
  4. Whent the test is complete, JMock verifies that all the expectations were satisfied

Interaction-Based Test: Mockito Example

/**
 * I test {@link WarehouseImpl}.
 */
public class WarehouseImplMockitoTest {

    // system under test (SUT)
    private Warehouse warehouse;

    // depended-on-components
    private InventoryService inventoryService;

    @Test
    public void shouldRemoveInventoryWhenContainsEnoughStockOfProduct() {

        // setup
        inventoryService = mock(InventoryService.class);
        warehouse = new WarehouseImpl(inventoryService);

        final int requiredAmount = 50;
        final String productName = "fakeProduct";

        // stubbing (part of set up really)
        stub(inventoryService.containsEnoughStock(requiredAmount, productName))
                .toReturn(true);

        // exercise test
        warehouse.removeFromInventoryIfAvailable(requiredAmount, productName);

        // behaviour verification
        verify(inventoryService).containsEnoughStock(requiredAmount,
                productName);
        verify(inventoryService).removeFromInventoryStock(requiredAmount,
                productName);
    }

}

Things to note:

  1. Using Mockito, we stub methods on our test spy of inventoryService to force execution down a praticular path.
  2. The behaviour verification is done after the test is executed (as test spy observes what happens during test execution which allows us to make assertions about the interactions later).
  3. Using mockito we do have assertions of a type; we assert only what we care about, if there were other interactions that occured that we don’t care about, we don’t have to make any assertion about them
  4. This interaction-based test feels exactly like our state-based test.

Can we have a test that verifies State and Interactions?

It is possible to write a simple test that verifies both the state of something and the interaction of the SUT with one of its components.

Using the last example we could of written the test as:

 @Test
    public void shouldRemoveInventoryWhenContainsEnoughStockOfProductAndReturnTrue() {

        // setup
        inventoryService = mock(InventoryService.class);
        warehouse = new WarehouseImpl(inventoryService);

        final int requiredAmount = 50;
        final String productName = "fakeProduct";

        // stubbing (part of set up really)
        stub(inventoryService.containsEnoughStock(requiredAmount, productName))
                .toReturn(true);

        // exercise test
        final boolean result = warehouse.removeFromInventoryIfAvailable(
                requiredAmount, productName);

        // verification
        // behaviour verification
        verify(inventoryService).containsEnoughStock(requiredAmount,
                productName);
        verify(inventoryService).removeFromInventoryStock(requiredAmount,
                productName);

        // state verification
        assertTrue(result);
    }

Its probably best to avoid this. It would be better to write two tests, one that concentrates expressing the interaction for whatever reason that is important and another that verifies the state returned from the method.

Observations

With regards the Classical versus Mockist TDD approaches, I largely favor the Mockist approach but do at times use real implementations as opposed to test doubles when they are simple objects that are easy to setup (zero components) such as Value objects.

On State-based versus Interaction-based tests: both types of tests will most likely need to be written when using TDD as a technique to develop.

Using ‘mocking frameworks’ such as JMock and Mockito helps keep the amount of test code. It allows a TDD’er to use TDD more as a design activity. We can quickly discover new types and behaviour needed for the system. Using Mockito I find allows for the writing of cleaner tests that better express the intention of the developer.

Bibliography

[1] Mocks Aren’t Stubs: Martin Fowler
[2] xUnit Test Patterns: Gerard Meszaros

Tags: , , , , , , , , , , ,

Leave a comment