为什么模拟对象没有得到方法调用?
Why does the mocked object not get a method call?
这两个单元测试相同,但模拟对象 utility
仅在第一个测试中收到调用。调用模拟 doTheThing()
的方法按预期运行。为什么模拟对象 utility
在两个测试中都没有收到调用?
我有 运行 这些测试
- 在 Eclipse 中
- 使用 mvn 命令
- 使用 java 命令 运行 JUnitCore class,在 class 路径
上使用 Junit、Easy Mock 和所需的库
我正在使用 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 也是这样做的。
这两个单元测试相同,但模拟对象 utility
仅在第一个测试中收到调用。调用模拟 doTheThing()
的方法按预期运行。为什么模拟对象 utility
在两个测试中都没有收到调用?
我有 运行 这些测试
- 在 Eclipse 中
- 使用 mvn 命令
- 使用 java 命令 运行 JUnitCore class,在 class 路径 上使用 Junit、Easy Mock 和所需的库
我正在使用 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 也是这样做的。