EasyMock最佳实践
上一篇 / 下一篇 2011-01-22 12:04:29 / 个人分类:单元测试
★EasyMock在录制的时候最典型的写法:
Java代码 ★如果有个要录制的方法只知道类型不知道具体的值, 可以这样写:
★出现这样的异常:
java.lang.IllegalStateException: 2 matchers expected, 1 recorded.
可能是设置mock方法的期望调用方式时, 既使用了isA的方式来指定参数, 又使用了一个具体值来作为参数
比如这样写:
正确的写法:
★andReturn()只是用于当mock对象的方法需要有返回值的情况下,手动设置这个方法的返回值给调用的测试类的。在本例中methodABC (arguments,……)方法就需要在recorder的时候用andReturn()方法指定返回值给TargetClass。如果对于有返回值的方法不指定其返回值,在测试的时候会抛出”java.lang.IllegalStateException: missing behavior. definition for the preceeding method call XXX”异常。
★一般不能这样写:
而应该这样写:
否则会抛出这样的异常:
java.lang.IllegalStateException: matcher calls were not used outside expectations
at org.easymock.internal.RecordState.replay(RecordState.java:72)
at org.easymock.internal.MocksControl.replay(MocksControl.java:57)
at org.easymock.EasyMock.replay(EasyMock.java:1280)也就是说, 返回值必须给一个具体的值, 而不能只指定返回值类型
★在实用expect来设置mock方法的期望调用方式时, 如果使用到基本类型, 但是又不要基本类型的值, 一般不要这样写:
而应该这样写:
★EasyMock还有一个很让人郁闷的地方, 比如一个方法的参数可能为null, 而你在测试的时候又恰恰传了一个空值, 则这个测试是没法通过的, 会出现类似下面的异常:
经过跟踪这个应该是EasyMock的一个bug:
不过这个问题也不是不能绕过, 我用了下面的做法:
后来我问了一下EasyMock开发者Tammo Freese, 看来不是能算一个bug, 他做了如下的回答:
★如果需要expect的方法没有返回值, 应该这样写:
先执行mock的要调用的方法, 然后调用EasyMock.expectLastCall().anyTimes();
★如果是对具体类进行mock, 则需要使用org.easymock.classextension.EasyMock去替换org.easymock.EasyMock, 当然这个需要加入对easymockclassextension的引用, 具体使用上则没有区别, 如果采用maven构建工程, 则可以采用下面的写法:
- expect(mockEmployeeRepository.findByFirstNameAndLastName("John", "Doe")).andReturn(employees);
Java代码
- expect(mockEmployeeRepository.findBySpecification(isA(EmployeeSearchSpecification.class))
- .andReturn(employees);
java.lang.IllegalStateException: 2 matchers expected, 1 recorded.
可能是设置mock方法的期望调用方式时, 既使用了isA的方式来指定参数, 又使用了一个具体值来作为参数
比如这样写:
Java代码
- expect(mockEmployeeRepository.findByDepartmentAndSpecification("HR",
- isA(EmployeeSearchSpecification.class)).andReturn(emplooyees);
Java代码
- expect(mockEmployeeRepository.findByDepartmentAndSpecification(eq("HR"),
- isA(EmployeeSearchSpecification.class)).andReturn(employees);
★一般不能这样写:
Java代码
- EasyMock.expect(itemPropertyManager.processPublishOrEditSpu(EasyMock.isA(SpuDO.class),
- EasyMock.isA(BaseResultDO.class))).andReturn(EasyMock.isA(BaseResultDO.class));
Java代码
- EasyMock.expect(itemPropertyManager.processPublishOrEditSpu(EasyMock.isA(SpuDO.class),
- EasyMock.isA(BaseResultDO.class))).andReturn(null));
引用
java.lang.IllegalStateException: matcher calls were not used outside expectations
at org.easymock.internal.RecordState.replay(RecordState.java:72)
at org.easymock.internal.MocksControl.replay(MocksControl.java:57)
at org.easymock.EasyMock.replay(EasyMock.java:1280)
★在实用expect来设置mock方法的期望调用方式时, 如果使用到基本类型, 但是又不要基本类型的值, 一般不要这样写:
Java代码
- EasyMock.expect(
- keywordsChecker.checkNormalKeywords(EasyMock
- .isA(String.class), EasyMock.isA(Long.class),
- EasyMock.isA(String.class))).andReturn("");
Java代码
- EasyMock.expect(keywordsChecker.checkNormalKeywords(EasyMock.isA(String.class), EasyMock.anyLong(),
- EasyMock.isA(String.class))).andReturn("");
引用
java.lang.AssertionError:
Unexpected method call checkFixKeywords(null, 50010815):
checkFixKeywords(isA(java.lang.String), <any>): expected: 1, actual: 0
checkNormalKeywords(isA(java.lang.String), <any>, isA(java.lang.String)): expected: 1, actual: 0
at org.easymock.internal.MockInvocationHandler.invoke(MockInvocationHandler.java:29)
at org.easymock.internal.ObjectMethodsFilter.invoke(ObjectMethodsFilter.java:45)
这也就要求被测试的方法, 参数不能传递空值. Unexpected method call checkFixKeywords(null, 50010815):
checkFixKeywords(isA(java.lang.String), <any>): expected: 1, actual: 0
checkNormalKeywords(isA(java.lang.String), <any>, isA(java.lang.String)): expected: 1, actual: 0
at org.easymock.internal.MockInvocationHandler.invoke(MockInvocationHandler.java:29)
at org.easymock.internal.ObjectMethodsFilter.invoke(ObjectMethodsFilter.java:45)
经过跟踪这个应该是EasyMock的一个bug:
Java代码
- public class InstanceOf implements IArgumentMatcher {
- private final Class<?> clazz;
- public InstanceOf(Class clazz) {
- this.clazz = clazz;
- }
- public boolean matches(Object actual) {
- // 问题在这里:
- return (actual != null) && clazz.isAssignableFrom(actual.getClass());
- // 应该这样写:
- return (actual == null) || clazz.isAssignableFrom(actual.getClass());
- }
- public void appendTo(StringBuffer buffer) {
- buffer.append("isA(" + clazz.getName() + ")");
- }
- }
Java代码
- EasyMock.expect(
- keywordsChecker.checkFixKeywords(
- (String) EasyMock.isNull(), EasyMock.anyLong()))
- .andReturn("");
- EasyMock.expect(
- keywordsChecker.checkFixKeywords(
- EasyMock.isA(String.class), EasyMock.anyLong()))
- .andReturn("").anyTimes();
引用
this is expected behavior, and it is also documented.
The isA() matcher does the same thing as instanceof , so for null, it returns false.
If you would like to match any Object, use
anyObject()
If you would like to match either Strings or null, use
or(isA(String.class), isNull())
这里录制了两个expect:将null和非空值分开, 但是第二个的返回值注意加上anyTimes(), 因为我的第二种情况会调用多次, 如果两种情况都会调用多次, 则都加上该方法即可, 否则会出现类似下面的异常: The isA() matcher does the same thing as instanceof , so for null, it returns false.
If you would like to match any Object, use
anyObject()
If you would like to match either Strings or null, use
or(isA(String.class), isNull())
引用
java.lang.AssertionError:
Unexpected method call checkFixKeywords("new test", 50010815):
checkFixKeywords(isA(java.lang.String), <any>): expected: 1, actual: 1 (+1)
checkNormalKeywords(isA(java.lang.String), <any>, isA(java.lang.String)): expected: 1, actual: 0
at org.easymock.internal.MockInvocationHandler.invoke(MockInvocationHandler.java:32)
at org.easymock.internal.ObjectMethodsFilter.invoke(ObjectMethodsFilter.java:61)
★静态方法是没法用EasyMock进行mock的 Unexpected method call checkFixKeywords("new test", 50010815):
checkFixKeywords(isA(java.lang.String), <any>): expected: 1, actual: 1 (+1)
checkNormalKeywords(isA(java.lang.String), <any>, isA(java.lang.String)): expected: 1, actual: 0
at org.easymock.internal.MockInvocationHandler.invoke(MockInvocationHandler.java:32)
at org.easymock.internal.ObjectMethodsFilter.invoke(ObjectMethodsFilter.java:61)
★如果需要expect的方法没有返回值, 应该这样写:
先执行mock的要调用的方法, 然后调用EasyMock.expectLastCall().anyTimes();
★如果是对具体类进行mock, 则需要使用org.easymock.classextension.EasyMock去替换org.easymock.EasyMock, 当然这个需要加入对easymockclassextension的引用, 具体使用上则没有区别, 如果采用maven构建工程, 则可以采用下面的写法:
Xml代码
- <!-- mock 相关 -->
- <dependency>
- <groupId>org.easymock</groupId>
- <artifactId>easymock</artifactId>
- <version>2.4</version>
- </dependency>
- <dependency>
- <groupId>org.easymock</groupId>
- <artifactId>easymockclassextension</artifactId>
- <version>2.2.1</version>
TAG:
- 引用 删除 candy_girl / 2011-01-22 12:08:38
-
★如果是对具体类进行mock, 则需要使用org.easymock.classextension.EasyMock去替换org.easymock.EasyMock, 当然这个需要加入对easymockclassextension的引用, 具体使用上则没有区别, 如果采用maven构建工程, 则可以采用下面的写法:
Xml代码
<!-- mock 相关 -->
<dependency>
<groupId>org.easymock</groupId>
<artifactId>easymock</artifactId>
<version>2.4</version>
</dependency>
<dependency>
<groupId>org.easymock</groupId>
<artifactId>easymockclassextension</artifactId>
<version>2.2.1</version>
</dependency>
<!-- mock 相关 end-->
★通常对一个方法进行测试的时候, mock一个对象的情况比较多见, 于是我写了下面的一个比较通用的抽象类:
Java代码
public abstract class AbstractMockExecutor<T> {
protected T mock;
/**
* @param clazz
* @return
*/
protected T createMock(Class<T> clazz) {
mock = EasyMock.createMock(clazz);
return mock;
}
public void execute() throws Exception {
record();
EasyMock.replay(mock);
invoke();
verify();
}
/**
* 创建mock对象, 并对要mock的方法进行方法录制, 必须在该方法中手动调用{@link #createMock(Class)}方法.<br>
* 该方法的一般做法如下:
*
* <pre>
* createMock(MockClass);
* EasyMock.expect(mock.mockMethod(mockArgument...)).andReturn(
* mockResult);
* BeanObject.setter(mock);
* </pre>
*
* @throws Exception
*/
protected abstract void record() throws Exception;
/**
* 调用经过mock之后的执行过程
*/
protected abstract void invoke() throws Exception;
/**
* 验证mock是否正确
*/
public void verify() {
EasyMock.verify(mock);
}
}
标题搜索
日历
|
|||||||||
日 | 一 | 二 | 三 | 四 | 五 | 六 | |||
1 | 2 | 3 | 4 | 5 | 6 | ||||
7 | 8 | 9 | 10 | 11 | 12 | 13 | |||
14 | 15 | 16 | 17 | 18 | 19 | 20 | |||
21 | 22 | 23 | 24 | 25 | 26 | 27 | |||
28 | 29 | 30 |
我的存档
数据统计
- 访问量: 59994
- 日志数: 61
- 建立时间: 2010-10-19
- 更新时间: 2013-05-30