This is another example where the last test actually validates that certain messages happen in a particular order. The test is called generatesCorrectSummaryReport and it creates a jMock “Sequence” that verifies the following:
- The method SummaryReportPrinter.displayTransactionSummary is called 5 times in a row with the values: 10, 20, 30, 40, 50
- Next, the method SummaryReportPrinter.displayTotalSales is called with a value of 150
- Finally, the method SummaryReportPrinter.displayBalance is called with a value of 483
- The test also allows SummaryReportPrinter.Transaction.getBalance() to be called any number of times
PointOfSaleTerminalTest
package com.objectmentor.post;
import static org.junit.Assert.assertEquals;
import junit.framework.JUnit4TestAdapter;
import org.jmock.Expectations;
import org.jmock.Mockery;
import org.jmock.Sequence;
import org.jmock.integration.junit4.JMock;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(JMock.class)
public class PointOfSaleTerminalTest {
public static junit.framework.Test suite() {
return new JUnit4TestAdapter(PointOfSaleTerminalTest.class);
}
Mockery context = new Mockery();
PointOfSaleTerminal pointOfSaleTerminal;
@Before
public void createPointOfSaleTerminal() {
pointOfSaleTerminal = new PointOfSaleTerminal();
}
@Test
public void canHaveInitialBalanceSetAndConfirmed() {
pointOfSaleTerminal.setBalance(100000);
assertEquals(100000, pointOfSaleTerminal.getBalance());
}
@Test
public void balanceReflectsSingleSale() {
final Transaction transacton = context.mock(Transaction.class);
context.checking(new Expectations() {
{
one(transacton).getAmountDue();
will(returnValue(15));
}
});
pointOfSaleTerminal.setBalance(27);
pointOfSaleTerminal.addTransaction(transacton);
assertEquals(42, pointOfSaleTerminal.getBalance());
}
private int calculateAmount(int index) {
return index * 10;
}
private void addTransaction(final int index) {
final Transaction transaction = context.mock(Transaction.class);
context.checking(new Expectations() {
{
ignoring(transaction).getAmountDue();
will(returnValue(calculateAmount(index + 1)));
}
});
pointOfSaleTerminal.addTransaction(transaction);
}
private void addTransactionSummaryExpectation(final SummaryReportPrinter summaryReportPrinter,
final Sequence printSequence, final int index) {
context.checking(new Expectations() {
{
one(summaryReportPrinter).displayTransactionSummary(with(equal(index)),
with(equal(calculateAmount(index))));
inSequence(printSequence);
}
});
}
@Test
public void generatesCorrectSummaryReport() {
final int extectedBalance = 333;
pointOfSaleTerminal.setBalance(extectedBalance);
for (int i = 0; i < 5; ++i) {
addTransaction(i);
}
final SummaryReportPrinter summaryReportPrinter = context.mock(SummaryReportPrinter.class);
final Sequence printSequence = context.sequence("printSequence");
context.checking(new Expectations() {
{
for (int i = 1; i <= 5; ++i) {
addTransactionSummaryExpectation(summaryReportPrinter, printSequence, i);
}
final int expectedTotal = 150;
one(summaryReportPrinter).displayTotalSales(with(equal(expectedTotal)));
inSequence(printSequence);
one(summaryReportPrinter).displayBalance(
with(equal(expectedTotal + extectedBalance)));
inSequence(printSequence);
}
});
pointOfSaleTerminal.setSummaryReportPrinter(summaryReportPrinter);
pointOfSaleTerminal.generateSummaryReport();
}
}
PointOfSaleTerminal
package com.objectmentor.post;
import java.util.LinkedList;
import java.util.List;
public class PointOfSaleTerminal {
List<Transaction> transactions = new LinkedList<Transaction>();
int initialBalance;
private SummaryReportPrinter summaryReportPrinter;
public void setBalance(int balance) {
this.initialBalance = balance;
}
public int getBalance() {
int balance = initialBalance;
for (Transaction transaction : transactions) {
balance += transaction.getAmountDue();
}
return balance;
}
public void addTransaction(Transaction transaction) {
transactions.add(transaction);
}
public void generateSummaryReport() {
int index = 0;
for (Transaction transaction : transactions) {
int amountDue = transaction.getAmountDue();
summaryReportPrinter.displayTransactionSummary(++index, amountDue);
}
int balance = getBalance();
int totalSales = balance - initialBalance;
summaryReportPrinter.displayTotalSales(totalSales);
summaryReportPrinter.displayBalance(balance);
}
public void setSummaryReportPrinter(SummaryReportPrinter summaryReportPrinter) {
this.summaryReportPrinter = summaryReportPrinter;
}
}
SummaryReportPrinter
package com.objectmentor.post;
public interface SummaryReportPrinter {
void displayTransactionSummary(int index, int totalAmount);
void displayTotalSales(int totalAmount);
void displayBalance(int amount);
}
Transaction
package com.objectmentor.post;
public interface Transaction {
int getAmountDue();
}
Comments