所以我确定那里有类似的东西,但我一直在寻找一个小时,却找不到我想要的东西。说我有一个看起来像这样的课:
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
}
答案 0 :(得分:15)
使用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();
}
}
有一些问题,所以看看relevant documentation也是如此。
答案 1 :(得分:5)
假设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和field注入;或者使用setter和field injection来使用构造函数注入。即使更改的构造函数不是将用于构造函数注入的构造函数,也会发生这种情况。
因此,任何使用构造函数注入的测试都会自动变脆;从某种意义上说,与测试本身没有直接关系的变化会导致测试失败。这样的故障可能很难排除故障。
@InjectMocks
注释旨在用于执行依赖注入的Spring等框架;对于使用Spring的类的测试,它可能是非常宝贵的。但是如果依赖注入不是你班级的一部分,我强烈建议避免@InjectMocks
由于其脆弱性。您确实希望您的测试代码与生产代码一样易于维护和排除故障。
答案 2 :(得分:3)
这是不推荐,但你可以侦察真实对象:)
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;
}
...
经过测试,有效;)
答案 3 :(得分:2)
我想你想看一下Mock对象。您可以创建MyClass的模拟,然后设置在调用myMethod时调用otherMethod()的期望,如果未调用则调整失败。
以下是对java的一个非常好的概述 - http://www.scalatest.org/user_guide/testing_with_mock_objects
使用Mocks的另一个主要好处是,您可以避免在测试中出现副作用,例如记录到NSLog或访问Web服务器或打印。