Case Study

Testing the Business Logic with Mocks

Previous Next
Here we will see how to use SpringUnit to create a unit test of business logic. We will create a test for the insertOrder method of PetStoreImpl. As we have already seen, insertOrder calls OrderDao and then ItemDao. PetStoreImpl (excerpt)
public class PetStoreImpl implements PetStoreFacade, OrderService {

	private ItemDao<Item> itemDao;
	private OrderDao<Order> orderDao;

	/* other methods and members omitted */
	
	public void insertOrder(Order order) {
		this.orderDao.insertOrder(order);
		this.itemDao.updateQuantity(order);
	}

}
The implementations of the DAO classes interact with the database; for this to be a unit test, we will need to mock their behavior. The case study uses the EasyMock framework for object mocking. The following excerpt from PetStoreImplTest.xml demonstrates how to create mocks using Spring bean configuration with a static factory method. PetStoreImplTest.xml (excerpt)
<beans>

	<bean id="itemDao" class="org.easymock.EasyMock" factory-method="createMock" singleton="false">
		<constructor-arg>
			<bean class="java.lang.Class" factory-method="forName">
				<constructor-arg><value>org.springunit.framework.samples.jpetstore.dao.ItemDao</value></constructor-arg>
			</bean>
		</constructor-arg>
	</bean>

	<bean id="orderDao" class="org.easymock.EasyMock" factory-method="createMock" singleton="false">
		<constructor-arg>
			<bean class="java.lang.Class" factory-method="forName">
				<constructor-arg><value>org.springunit.framework.samples.jpetstore.dao.OrderDao</value></constructor-arg>
			</bean>
		</constructor-arg>
	</bean>
	
	<!-- other beans omitted -->

</beans>
Here is the code for the test. The test retrieves the subject and the input order from the SpringUnit context. References to each of the DAOs are obtained from the subject and stored in an array. Now, the expected behavior of the mocks is established, calling insertOrder first on the orderDao, then updateQuantity on itemDao. The call to replayMocks tells the EasyMock framework that all mocked behavior has been coded. Next, the test calls the method under test, insertOrder, and then verifyMocks. verifyMocks checks that the behavior exhibited by the call to insertOrder matches the expected behavior programmed above.

PetStoreImplTest.java (excerpt)

	public void testInsertOrder() throws Exception {
		PetStoreImpl subject = getObject("subject");
		Order order = getObject("order");
		ItemDao<Item> itemDao = subject.getItemDao();
		OrderDao<Order> orderDao = subject.getOrderDao();
		Object[] mocks = new Object[]{itemDao, orderDao};
		
		orderDao.insertOrder(order);
		itemDao.updateQuantity(order);
		EasyMock.replay(mocks);
		
		subject.insertOrder(order);
		EasyMock.verify(mocks);
	}

Finally, here are elements of the Spring configuration file that are relevant to this test. First, notice how the mocked DAOs are wired to the subject. Next, note carefully how the subject is declared in the scope where singleton="false". This causes every subsequent reference within this file to cause the generation at run-time of a new instance of PetStoreImpl. Finally, see how the subject and order are declared in the scope for this test. Notice that order reuses a test data value from OrderData.xml: order1 is a non-singleton instance of an Order object.

PetStoreImplTest.xml (excerpt)

<beans>
	
	<bean id="subject" class="org.springunit.framework.samples.jpetstore.domain.logic.PetStoreImpl" singleton="false">
		<property name="itemDao">
			<ref local="itemDao"/>
		</property>
		<property name="orderDao">
			<ref local="orderDao"/>
		</property>
		<!-- similarly for other DAOs -->
	</bean>

	<import resource="classpath:OrderData.xml"/>  <!-- order1 comes from here -->
	<!-- other imports omitted -->

	<bean id="petStoreImplTest" class="org.springunit.framework.SpringUnitContext">
		<property name="data">
			<map>
				<entry key="testInsertOrder">
					<map>
						<entry key="subject">
							<ref local="subject"/>
						</entry>
						<entry key="order">
							<ref bean="order1"/>
						</entry>
					</map>
				</entry>
				<!-- other entries omitted -->
			</map>
		</property>
	</bean>
	
	<!-- other beans omitted -->
	
</beans>

Previous Next