为什么模拟对象没有得到方法调用?

Why does the mocked object not get a method call?

这两个单元测试相同,但模拟对象 utility 仅在第一个测试中收到调用。调用模拟 doTheThing() 的方法按预期运行。为什么模拟对象 utility 在两个测试中都没有收到调用?

我有 运行 这些测试

我正在使用 Easy Mock 4.0.2 和 Junit 4.12。

组件测试class

import static org.easymock.EasyMock.anyString;
import static org.easymock.EasyMock.expect;

import org.easymock.EasyMockRunner;
import org.easymock.EasyMockSupport;
import org.easymock.Mock;
import org.easymock.TestSubject;
import org.junit.Test;
import org.junit.runner.RunWith;

@RunWith(EasyMockRunner.class)
public class ComponentTest extends EasyMockSupport {
    @TestSubject
    private Component component = new Component();
    @Mock
    private Utility utility;

    @Test
    public void testDoTheThing1() {
        Context.setUtility(utility);
        expect(utility.doSomethingWith(anyString())).andReturn(null);
        replayAll();
        component.doTheThing("aa");
        verifyAll();
        resetAll();
    }

    @Test
    public void testDoTheThing2() {
        Context.setUtility(utility);
        expect(utility.doSomethingWith(anyString())).andReturn(null);
        replayAll();
        component.doTheThing("aa");
        verifyAll();
        resetAll();
    }
}

组件class

public class Component implements Processor{
    public String doTheThing(String request) {
        return UTILITY.doSomethingWith(request);
    }
}

处理器接口

public interface Processor {
    Utility UTILITY = Context.getUtility();
}

上下文class

public class Context {
    private static Utility utility;

    public static Utility getUtility(){
        return utility;
    }

    public static void setUtility(Utility utility) {
        Context.utility = utility;
    }
}

实用程序class

public class Utility {
    public String doSomethingWith(String request) {
        return null;
    }
}

J单元输出

There was 1 failure:
1) testDoTheThing2(ComponentTest)
java.lang.AssertionError: 
  Expectation failure on verify:
    Utility.doSomethingWith(<any>): expected: 1, actual: 0
    at org.easymock.internal.MocksControl.verify(MocksControl.java:242)
    at org.easymock.EasyMockSupport.verifyAll(EasyMockSupport.java:523)
    at ComponentTest.testDoTheThing2(ComponentTest.java:41)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:566)
    at org.junit.runners.model.FrameworkMethod.runReflectiveCall(FrameworkMethod.java:50)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:290)
    at org.junit.runners.ParentRunner.schedule(ParentRunner.java:71)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
    at org.junit.runners.ParentRunner.access[=15=]0(ParentRunner.java:58)
    at org.junit.runners.ParentRunner.evaluate(ParentRunner.java:268)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    at org.junit.runners.Suite.runChild(Suite.java:128)
    at org.junit.runners.Suite.runChild(Suite.java:27)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:290)
    at org.junit.runners.ParentRunner.schedule(ParentRunner.java:71)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
    at org.junit.runners.ParentRunner.access[=15=]0(ParentRunner.java:58)
    at org.junit.runners.ParentRunner.evaluate(ParentRunner.java:268)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
    at org.junit.runner.JUnitCore.run(JUnitCore.java:115)
    at org.junit.runner.JUnitCore.runMain(JUnitCore.java:77)
    at org.junit.runner.JUnitCore.main(JUnitCore.java:36)

发件人:https://docs.oracle.com/javase/tutorial/java/IandI/interfaceDef.html

All constant values defined in an interface are implicitly public, static, and final.

因此,当每个测试方法为 运行 时,都会创建一个新的 Utility mock,而 Processor.UTILITY 隐含地是一个静态最终常量,它将只保存它的第一个赋值 - 这将是值来自第一个单元测试。

因此,您应该使用“static final Utility”而不是@Mock Utility,并在所有测试方法中使用该单个实例。

编辑添加:请注意,在每个单独的测试方法 运行 之前,每个 class 带有 @TestSubject 和 @Mock 注释的成员在每个测试中都会重新创建新的,并且这些新模拟是注入新的测试对象。这最大限度地减少了状态/行为从一个测试到另一个测试的遗留。巧的是,Mockito 也是这样做的。