这是一个关于如何使用模拟对象对Java类进行单元测试的一般问题。
我可以用这个例子来总结我的问题。假设我有一个名为MyInterface.java的接口和一个不覆盖equals()的“ TwoString”对象
“ TwoString.java”
private String string1;
private String string2;
public TwoString(String string1, String string2) {
this.string1 = string1;
this.string2 = string2;
}
...getters..setters..
“ MyInterface.java”
void callMe(TwoString twoString);
然后,我有“ MyClass.java”对象。它的构造函数接受MyInterface的具体实现。
MyClass methodToTest()包含以某种方式创建TwoString对象的逻辑。假设它将被创建为
new TwoString("a","b")
因此,在调用methodToTest()时,它将创建此TwoString对象,该对象将传递给接口方法callMe(TwoString twoString)。
我基本上想模拟接口。使用此模拟创建MyClass对象。然后,验证是否使用TwoString的特定实例调用了模拟方法。
我正在使用EasyMock,这是一些Java代码
“ MyClassTest.java”
public void test() throws Exception {
MyInterface myInterfaceMock = createMock(MyInterface.class);
MyClass myClass = new MyClass(myInterfaceMock);
myInterfaceMock.callMe(new TwoString("a","b")); <--- fails here
expectLastCall();
replay(myInterfaceMock);
myClass.methodToTest();
verify(myInterfaceMock);
问题来了。我在通话中期望的TwoString对象
myInterfaceMock.callMe(new TwoString("a","b"));
与MyClass.methodToTest()中生成的代码不同,因为TwoString.java不会覆盖equals。
我可以使用TwoString实例跳过该问题
myInterfaceMock.callMe((TwoString)anyObject());
但是我想确定接口方法是使用TwoString的特定实例调用的,该实例包含“ a”作为string1和“ b”作为string2。
在这种情况下,TwoString对象非常简单,将很容易覆盖equals方法-但是如果我需要检查更复杂的对象该怎么办。
谢谢
编辑:
我将通过此示例使它更具可读性
public class MyClassTest {
private MyClass myClass;
private TaskExecutor taskExecutorMock;
@Before
public void setUp() throws Exception {
taskExecutorMock = createMock(TaskExecutor.class);
myClass = new MyClass(taskExecutorMock);
}
@Test
public void testRun() throws Exception {
List<MyObj> myObjList = new ArrayList<MyObj>();
myObjList.add(new MyObj("abc", referenceToSomethingElse));
taskExecutorMock.execute(new SomeTask(referenceToSomethingElse, ???new SomeObj("abc", referenceToSomethingElse, "whatever"))); <--- ??? = object created using data in myObjList
expectLastCall();
replay(taskExecutorMock);
myClass.run(myObjList);
verify(taskExecutorMock);
}
}
SomeObj =由myClass.run()使用myObjList中包含的数据创建的对象。
假设SomeObj来自第三方库,它不会覆盖equals。
我想确保使用该SomeObj的特定实例调用taskExecutorMock.execute()方法
如何测试myClass.run()实际是否使用正确的实例调用taskExecutorMock方法
最佳答案
可以使用org.easymock.IArgumentMatcher
使用自定义等于匹配方法。
它看起来应该像这样:
private static <T extends TwoString> T eqTwoString(final TwoString twoString) {
reportMatcher(new IArgumentMatcher() {
/** Required to get nice output */
public void appendTo(StringBuffer buffer) {
buffer.append("eqTwoString(" + twoString.getString1() + "," + twoString.getString2() + ")");
}
/** Implement equals basically */
public boolean matches(Object object) {
if (object instanceof TwoString) {
TwoString other = (TwoString) object;
// Consider adding null checks below
return twoString.getString1().equals(object.getString1()) && twoString.getString2().equals(object.getString2());
}
else {
return false;
}
}
});
return null;
}
并使用如下:
myInterfaceMock.callMe(eqTwoString(new TwoString("a","b")));
一些细节可能不正确,但从本质上讲,这是我之前所做的。 in the EasyMock documentation还有另一个示例和更详尽的解释。只需搜索
IArgumentMatcher
。