Currently, the major approach for java unit test are built on two major components –
- Junit – The unit test framework
- EasyMock and EasyMock Extension – Which are used to build mock test
What’s problem on Mock Test? It costs a lot time on preparation
Mock
test is a very good way to test unit of codes. I still prefer mock test
as the major approach of unit test. However, mock test has its own
problem.
The major steps on Mock Test is –
- Assume we are going to test “Output ServiceA.MethodA(Input input)”, firstly, get an instance of ServiceA
- Create an Input for methodA, which generally need new an object and invoke many setter methods to set the values
- If
this method will call ServiceB.MethodB, we need create a mock object
for ServiceB, and create an ArugmentMather for methodB to match the
arguments, and create a return object for methodB
- Then we
invoke ServiceA.MethodA and internally ServiceA.MethodA will invoke
ServiceB.MethodB, and finally, we get the Output object
- At the last step, we will assert the Output object.
In order to test ServiceA.MethodA, we did lots of things, and most of things are very time-consuming activities, such as
- creating Input object,
- creating Mock service,
- creating ArgumentMacher for mock method, and
- creating return object for mock method
- And assert Output object
What’s my expectation?
- creating Input object – Can it be created automatically?
- creating Mock service – Can it be created automatically?
- creating ArgumentMacher for mock method, and – Can we NOT need create a new class for it?
- creating return object for mock method – Can it be created automatically?
- And assert Output object – Instead of equals() method, can we compare two object by values?
How can Unitils help us?
Unitils
is an open source library aimed at making unit testing easy and
maintainable. Unitils builds further on existing libraries like dbunit
and integrates with JUnit and TestNG .
Unitils provides
general asserion utilities, support for database testing, support for
testing with mock objects and offers integration with Spring ,
Hibernate and the Java Persistence API (JPA).
- General testing utilities
Equality assertion through reflection, with different options like
ignoring Java default/null values and ignoring order of collections
- EasyMock integration support
- Simplify EasyMock mock object creation
- Simplify mock object injection
- EasyMock argument matching using reflection equality
Back to our problem –
- Can
we initialize a Input or Mock Method Returned Object automatically? In
other words, creating an instance of a specific class, and fill all
attributes by random values. Unfortunately, Unitils doesn’t have direct
support on it. But i’ve created a simple util to initialize an bean
based on Unitils.
1 //for BeanInitializer.initializeSimpleBean, it is an simple tool to initialize a bean by random values. I didn't find a good tool for it, so, i write a simple one.
2 LogStatisticRawDataInput input = (LogStatisticRawDataInput) BeanInitializer.initializeSimpleBean(LogStatisticRawDataInput.class);
- Can a mock object be created automatically? Yes, Unitils provides an annotation ”@ReguarMock” to support it
1 public class SearchStatisticServiceImplTest extends com.starcite.commonsearch.test.Test {
2
3
4
5 @RegularMock
6
7 private StatisticAccess mockAccess; //just it
8
9
10
11 private SearchStatisticService statisticService;
12
13
14
15 @Before
16
17 public void setUp() {
18
19 statisticService = new SearchStatisticServiceImpl();
20
21 ((SearchStatisticServiceImpl)statisticService).setStatisticAccess(mockAccess);
22
23 }
24
25
26
27 }
- Can we compare the expected object and the real object by
contents? Of course, no need write the equals by yourself. Yes, Unitils
provides “Equality assertion through reflection, with different options
like ignoring Java default/null values and ignoring order of
collections”
1 Map<String, Integer> expectedKeywordFreqMap = new HashMap<String, Integer>();
2
3 Map<String, Integer> keywordFreqMap = output.getKeywordFreqMap();
4 ReflectionAssert.assertReflectionEquals(expectedKeywordFreqMap, keywordFreqMap); //that's it
- Can we create AugmentMatcher easier? Yes, Unitils provides “EasyMock argument matching using reflection equality”.
1 //parameter matcher
2
3 StatRawDataImpl rawData = new StatRawDataImpl();
4
5 rawData.setKeyword(input.getKeyword());
6
7 rawData.setLocation(input.getLocation());
8
9 rawData.setAccountID(input.getUserID());
10
11 rawData.setCreatedDate(new Date());
12
13 rawData.setSiteID(input.getSiteID());
14
15 rawData.setUniqueID(input.getSearchID());
16
17
18 List<statsearchrank> searchRankList = new ArrayList</statsearchrank><statsearchrank>();
19
20 for (int i = 0; i < SEARCH_RESULT_SIZE; i++) {
21
22 Long externalVendorID = searchResults.get(i);
23
24 StatSearchRank rank = new StatSearchRankImpl();
25
26 rank.setRank((input.getPageNum() - 1) * //current page number
27
28 (input.getKeywordLocationPreferredSize() + input.getPageSize()) //total page size
29
30 + i + 1);
31
32 rank.setExternalVendorID(externalVendorID);
33
34 searchRankList.add(rank);
35
36 }
37
38 mockAccess.logStatisticRawData(
39
40 EasyMockUnitils.refEq(rawData, ReflectionComparatorMode.LENIENT_DATES), //that's it, no need argument matcher
41
42 EasyMockUnitils.refEq(searchRankList));
43
44 EasyMock.expectLastCall().once();
45
46 EasyMockUnitils.replay();
47
Overall, Unitils is a pretty good tool to simplify unit test codes. Here we only mentioned Mock test, actually, Unitils can also simplify DB test/Spring Test etc. We will explore these futures later.
posted on 2009-03-30 22:30
Justin Chen 阅读(2000)
评论(1) 编辑 收藏 所属分类:
Unit Test & Mock Test