测试是否调用了另一种方法

所以我确定那里有类似的东西,但我一直在寻找一个小时,并没有找到我正在寻找的东西。 说我有一个看起来像这样的课:

public class MyClass { public void myMethod(boolean shouldCallOtherMethod) { if(shouldCallOtherMethod) { otherMethod(); } } public void otherMethod() { System.out.println("Called"); } } 

我如何制作这样的作品呢?

 @Test public void shouldCallMethod() { MyClass myClass = new MyClass(); myClass.myMethod(true) // verify myClass.otherMethod method was called } 

使用Mockito ,你可以对这样的真实物体进行间谍活动

 import org.junit.Test; import static org.mockito.Mockito.*; public class MyClassTest { @Test public void otherMethodShouldBeCalled() { MyClass myClass = new MyClass(); MyClass spy = spy(myClass); spy.myMethod(true); verify(spy).otherMethod(); } } 

有一些问题,所以也看一下相关的文档 。

假设MokeysClass有一个像这样声明的构造函数,其中Foo是其他类。

 public MokeysClass(String name, int counter, Foo myFoo) 

我会像这样写我的测试。

 @RunWith(MockitoJUnitRunner.class) public class TestArray { @Mock private Foo mockMyFoo; private String nameToInject = "Mokey"; private int counterToInject = 42; @Spy private MokeysClass toTest = new MokeysClass(nameToInject, counterToInject, mockMyFoo); @Test public void shouldCallMethod() { toTest.myMethod(true); verify(toTest).otherMethod(); } } 

所以我明确说明在创建测试对象时要调用哪个构造函数,以及传递给它的参数。

有一些原因不依赖@InjectMocks为我执行此步骤,特别是如果被测试的类更复杂并且具有多个构造函数。 Mockito选择具有最多参数的构造函数,但如果有多个构造函数具有相同数量的参数,Mockito可以选择任何构造函数; 也就是说,行为是未定义的。

一旦Mockito选择了构造函数,它就会检查该构造函数是否实际上可以用于构造函数注入。 如果,将不使用构造函数注入

  • 所选构造函数的一个或多个参数是基本类型,
  • 所选构造函数的一个或多个参数的类型是最终类,
  • 所选构造函数的一个或多个参数的类型是私有类,
  • 该类的唯一构造函数是默认构造函数。

如果这些条件中的任何一个成立,对于Mockito选择的构造函数,则不会使用构造函数注入。 在这种情况下,类必须具有默认构造函数,否则Mockito将抛出exception。

Mockito在选择是否应用构造函数注入时使用的标准的复杂性意味着添加或删除构造函数或更改构造函数的参数可以使Mockito从使用构造函数注入切换到使用setter和field注入; 或者使用setter和field injection来使用构造函数注入。 即使更改的构造函数不是将用于构造函数注入的构造函数,也会发生这种情况。

因此,任何使用构造函数注入的测试都会自动变得非常脆弱; 从某种意义上说,与测试本身没有直接关系的变化会导致测试失败。 这样的故障可能很难排除故障。

@InjectMocks注释被设计用于执行dependency injection的Spring等框架; 对于使用Spring的类的测试,它可能是非常宝贵的。 但是如果dependency injection不属于你的类,我强烈建议避免使用@InjectMocks ,因为它的脆弱性。 您确实希望您的测试代码像生产代码一样易于维护和排除故障。

不推荐 ,但你可以窥探真实的对象:)

 import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Spy; import org.mockito.runners.MockitoJUnitRunner; import static org.mockito.BDDMockito.verify; @RunWith(MockitoJUnitRunner.class) public class MyClassTest { @Spy private MyClass sut; // System Under Test @Test public void shouldCallMethod() { // when sut.myMethod(true); // then verify(sut).otherMethod(); } } 

结果:

 Tests Passed: 1 passed in 0,203 s 

更改代码后: sut.myMethod(false);

 Wanted but not invoked: sut.otherMethod(); -> at my.custom.MyClassTest.shouldCallMethod(MyClassTest.java:23) 

来源: 窥探真实物体


带构造函数注入的魔术版

 @Mock private LexAnalyzer lexAnalyzer; @Spy @InjectMocks private SyntaxAnalyzer sut; // System Under Test @Test public void shouldCallMethod() { // when sut.myMethod(true); // then verify(sut).otherMethod(); } 

SyntaxAnalyzer.java

 public class SyntaxAnalyzer { private final LexAnalyzer lexAnalyzer; public SyntaxAnalyzer(LexAnalyzer lexAnalyzer) { this.lexAnalyzer = lexAnalyzer; } ... 

经过测试,有效;)

我想你想看看Mock对象。 您可以创建MyClass的模拟,然后设置在调用myMethod时调用otherMethod()的期望,如果未调用则调整失败。

以下是对java的非常好的概述 – http://www.scalatest.org/user_guide/testing_with_mock_objects

使用Mocks的另一个主要好处是,您可以避免在测试中产生副作用,例如记录到NSLog或访问Web服务器或打印。