Injecting Mock Objects Example
This section was taken from Staale Pedersen's article at http://folk.uio.no/staalep/aop/testing.html. Thanks Staale for putting together some ideas on how you can use JBoss AOP for use in unit testing. The use of unit testing has increased tremendously lately, and many developers have seen the increase in quality and speed that comes from having a comprehensive unit-test suite. As the use of unit testing has increased, so have the number of situations where writing test are troublesome or maybe impossible. A common problem with writing tests is that it can require large amount of setup code. Testing code that rely on a remote system or data access from file/db/net can be almost impossible to implement. But with the help of JBoss AOP and mock objects this is no longer any problem. In this example we will examine a common situation where writing unit tests is difficult, but desirable. For simplicity we will use POJO's, but the example can easily be translated for a large J2EE application. 8.2.1. Required Knowledge This article focuses on unit testing with JUnit using Mock Maker and of course JBoss AOP. Knowledge of JUnit and JBoss AOP is required, Mock Maker is used, but thoroughly knowledge is not required. The example source code is compiled with Ant, env JUNIT_HOME must be set (mock maker and JBoss AOP jars are included in the example source). 8.2.2. The Problem The situation is common, we have a Bank application that manages Customers which can have one or more BankAccounts. The Bank has different business methods to calculate interest, accept loans, etc. (in production code this would be large and complex methods.) We want to write tests for the Bank's business methods to make sure they work as intended and that we don't introduce bugs if we refactor, extend, modify etc. The Bank has three business methods. package bank; import java.util.ArrayList; import customer.*; public class BankBusiness { private BankAccountDAO bankAccountDAO; public BankBusiness() { try { bankAccountDAO = BankAccountDAOFactory.getBankAccountDAOSerializer(); } catch(Exception e) { System.out.println(e.getMessage()); } } public boolean creditCheck(Customer c, double amount) { return (getSumOfAllAccounts(c) < amount * 0.4); } public double calculateInterest(BankAccount account) { if(account.getBalance() < 1000) return 0.01; else if(account.getBalance() < 10000) return 0.02; else if(account.getBalance() < 100000) return 0.03; else if(account.getBalance() < 1000000) return 0.05; else return 0.06; } public double getSumOfAllAccounts(Customer c) { double sum = 0; if(c.getAccounts().size() < 1) return sum; else { for(int i=0; i < c.getAccounts().size(); i++) { BankAccount a = bankAccountDAO.getBankAccount( ((Long) c.getAccounts().get(i)).longValue()); if(a != null) sum += a.getBalance(); } } return sum; } } calculateInterest(BankAccount b) can easily be tested since it is only dependent on the object it recieves as a parameter. creditCheck(Customer c, double amount) and getSumOfAllAccounts(Customer) are more complicated since they are data dependent. It uses a DAO layer to fetch all BankAccounts for a specified customer. The test should not be dependent of the DAO implementation since its goal is to check the business logic, not the DAO layer. In this example the DAO implementation is a simple serializer, but it could easily be an Entity beans, Hibernate, etc..