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



所以我确信有这样的东西,但我已经搜索了一个小时,还没有找到我想要的东西。假设我有一个类看起来像这样:

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将抛出异常。

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

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

@InjectMocks注释是为与Spring等进行依赖注入的框架一起使用而设计的;对于使用Spring的类的测试来说,它可能是非常宝贵的。但是,如果依赖注入不是类的一部分,我强烈建议避免使用@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)

来源:刺探真实物体


带有构造函数注入的Magic版本

@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的mock,然后设置期望值,即在调用myMethod时调用otherMethod(),如果未调用则失败。

下面是一个非常好的java概述http://www.scalatest.org/user_guide/testing_with_mock_objects

使用Mocks的另一个主要好处是,您可以避免测试中的副作用,如登录NSLog或访问web服务器或打印)。

相关内容

  • 没有找到相关文章

最新更新