Dynamic Returns with Easy Mock
Previously I posted a little demonstration of capturing parameters passed into a mock with the newest version of Easy Mock. This was handy for those situations where you want to make assertions about how a class under test interacts with its collaborators. In this post I will show another cool new feature of Easy Mock: dynamic mock method returns values
Let’s say you are writing a test for a point of sale terminal. You want to assert that the terminal correctly computes the total for the order by adding the total cost of goods sold and applicable taxes together. Let’s assume that the PointOfSaleTerminal class being tested uses an implementation of a TaxCalculator interface to compute the tax for each order. This test case could look something like this:
public class WhenComputingOrderTotal {
private PointOfSaleTerminal terminal;
@Before
public void inContext() {
TaxCalculator calculator = ...
terminal = new PointOfSaleTerminal(calculator);
}
@Test
public void shouldAddTaxWithTotalPrice() {
assertThat(terminal.totalFor(new Order(100)), is(108.0));
}
@Test
public void shouldAddTaxWithDifferentTotalPrice() {
assertThat(terminal.totalFor(new Order(50)), is(54.0));
}
}
So we could create a dummy implementation of TaxCalculator which provides a well behavior for tax calculation (ex. tax = total + total * 0.08). This is actually probably the preferred way to go, but let’s assume that you want to use a mock for this task. Maybe, the TaxCalculator interface has a bunch of other methods that you don’t want to stub out. Sure an IDE can generate these but they do obscure the purpose of the stub.
With Easy Mock 2.2 you can provide a callback method that is invoked when the mocked method is invoked. The return of this callback method is then passed along as the result of the method. One implementation of this is:
@Before
public void inContext() {
TaxCalculator calculator = createMock(TaxCalculator.class);
calculator.computeTaxForPurchaseOf(anyDouble());
expectLastCall().andAnswer(new IAnswer<Double>() {
@Override
public Double answer() throws Throwable {
Double totalPrice = (Double) getCurrentArguments()[0];
return totalPrice * 0.08;
}
});
replay(calculator);
terminal = new PointOfSaleTerminal(calculator);
}
This isn’t a trick I use too frequently, but its a nice tool to keep around for a rainy day.