为什么模拟对象无法获得方法调用?

时间:2019-09-07 19:16:37

标签: java junit4 easymock

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

我已经进行了这些测试

  • 在Eclipse中
  • 使用mvn命令
  • 通过运行JUnitCore类的Java命令,类路径上的Junit,Easy Mock和所需的库

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

ComponentTest类

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();
    }
}

组件类

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

处理器接口

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

上下文类

public class Context {
    private static Utility utility;

    public static Utility getUtility(){
        return utility;
    }

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

实用程序类

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

Junit输出

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$1.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$3.run(ParentRunner.java:290)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
    at org.junit.runners.ParentRunner$2.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$3.run(ParentRunner.java:290)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
    at org.junit.runners.ParentRunner$2.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)

1 个答案:

答案 0 :(得分:1)

来自:https://docs.oracle.com/javase/tutorial/java/IandI/interfaceDef.html

  

接口中定义的所有常量值都是隐式的public,static和final。

因此,当运行每个测试方法时都会创建一个新的Utility模拟,而Processor.UTILITY隐式是一个静态最终常量,它将仅保留其第一个分配的值-该值将是第一个单元测试的值。

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

要添加的编辑:请注意,在运行每个单独的测试方法之前,每个测试都会重新创建带有@TestSubject和@Mock注释的每个类成员,并将这些新的模拟物注入到新的测试主题中。这样可以最大程度地减少状态/行为从一个测试到另一个测试的影响。巧合的是,Mockito也这样做。