单元测试 - 使用不覆盖等于的对象检查方法调用

mic*_*son 1 java testing unit-testing easymock mocking

这是关于如何使用模拟对象对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..
Run Code Online (Sandbox Code Playgroud)

"MyInterface.java"

void callMe(TwoString twoString);
Run Code Online (Sandbox Code Playgroud)

然后我有"MyClass.java"对象.它的构造函数接受MyInterface的具体实现.
MyClass methodToTest()包含以某种方式创建TwoString对象的逻辑.假设它将被创建为

new TwoString("a","b")
Run Code Online (Sandbox Code Playgroud)

因此,当调用methodToTest()时,它会创建这个将传递给接口方法callMe(TwoString twoString)的TwoString对象.

我基本上想要模拟界面.使用此mock创建一个MyClass对象.然后验证是否使用TwoString的特定实例调用了mock方法.

我正在使用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);
Run Code Online (Sandbox Code Playgroud)

这就是问题所在.我期待在调用中的TwoString对象

myInterfaceMock.callMe(new TwoString("a","b"));
Run Code Online (Sandbox Code Playgroud)

与MyClass.methodToTest()中生成的不同,因为TwoString.java不会覆盖equals.

我可以跳过TwoString实例上的问题

myInterfaceMock.callMe((TwoString)anyObject());
Run Code Online (Sandbox Code Playgroud)

但我想确保使用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);
    }
}
Run Code Online (Sandbox Code Playgroud)

SomeObj = myClass.run()使用myObjList中包含的数据创建的对象.
假设SomeObj来自第三方库,它不会覆盖equals.

我想确保使用SomeObj的特定实例调用taskExecutorMock.execute()方法

我如何测试myClass.run()实际上正在使用正确的实例调用taskExecutorMock方法

wax*_*ing 5

可以使用自定义等于匹配方法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;
}
Run Code Online (Sandbox Code Playgroud)

用法如下:

myInterfaceMock.callMe(eqTwoString(new TwoString("a","b")));
Run Code Online (Sandbox Code Playgroud)

一些细节可能不正确,但实质上它是我以前做过的.EasyMock文档中提供另一个示例和更全面的解释.只是搜索IArgumentMatcher.