Mockito将模拟注入Spy对象

Wil*_*ild 22 java unit-testing dependency-injection mockito

我正在为一个具有2级依赖注入的类编写测试用例.我使用@Spy注释作为1级依赖注入对象,我想模拟第二级注入.但是,我一直在第二级获得空指针异常.有没有办法将模拟注入@Spy对象?

public class CarTestCase{
    @Mock
    private Configuration configuration;

    @Spy 
    private Engine engine;

    @InjectMocks 
    private Car car;

    @Test
    public void test(){

       Mockito.when(configuration.getProperties("")).return("Something");
       car.drive();
    }

}

public class Car{
    @Inject
    private Engine engine;

    public void drive(){
        engine.start();
    }
}

public class Engine{
    @Inject 
    private Configuration configuration;

    public void start(){
        configuration.getProperties();   // null pointer exception
    }

}
Run Code Online (Sandbox Code Playgroud)

Yoo*_* N. 27

我也徘徊如何将模拟注入间谍.

下面的方法将无法正常工作:

@Spy
@InjectMocks
private MySpy spy;
Run Code Online (Sandbox Code Playgroud)

但是,当使用注释和手动模拟时,可以通过"混合"方法实现期望的行为.以下工作完美:

@Mock
private NeedToBeMocked needToBeMocked;

@InjectMocks
private MySpy mySpy;

@InjectMocks
private SubjectUnderTest sut;

@BeforeMethod
public void setUp() {
    mySpy = Mockito.spy(new MySpy());
    MockitoAnnotations.initMocks(this);
}
Run Code Online (Sandbox Code Playgroud)

(SubjectUnderTest这取决于MySpy,并MySpy依次NeedToBeMocked).

UPD:就个人而言,我认为如果你不得不经常做这样的魔术,这可能表明你的类之间的依赖关系有问题,并且值得进行一些重构来改进你的代码.

  • 说实话,我真的不明白.但它完美地工作:) (2认同)

Ahm*_*wan 18

对我有用的(最简单的)解决方案。

@InjectMocks
private MySpy spy = Mockito.spy(new MySpy());
Run Code Online (Sandbox Code Playgroud)

MockitoAnnotations.initMocks(this)在这种情况下不需要,只要测试类用@RunWith(MockitoJUnitRunner.class).


Ser*_*hyr 11

Mockito不能进行如此棘手的注射,因为它不是注射框架.因此,您需要重构代码以使其更易于测试.使用构造函数注入很容易完成:

public class Engine{
    private Configuration configuration;

    @Inject 
    public Engine(Configuration configuration) {
        this.configuration = configuration;
    }
    ........
}

public class Car{
    private Engine engine;

    @Inject    
    public Car(Engine engine) {
        this.engine = engine;
    }
}
Run Code Online (Sandbox Code Playgroud)

在这种情况下,您必须手动处理模拟和注入:

public class CarTestCase{

    private Configuration configuration;

    private Engine engine;

    private Car car;

    @Before
    public void setUp(){
        configuration = mock(Configuration.class);
        engine = spy(new Engine(configuration));
        car = new Car(engine);
    }

    @Test
    public void test(){

       Mockito.when(configuration.getProperties("")).return("Something");
       car.drive();
    }

}
Run Code Online (Sandbox Code Playgroud)

  • 我明白了,但是Spring框架中的一般设计是人们将注入放在构造函数中吗?那么Inject注解的目的是什么呢? (2认同)

小智 6

我在使用Spring启动框架进行单元测试期间也遇到了这个问题,但我找到了一个使用@Spy和@InjectMocks的解决方案

以前的回答来自Yoory N.

@Spy
@InjectMocks
private MySpy spy;
Run Code Online (Sandbox Code Playgroud)

因为InjectMocks需要创建实例,所以适合我的解决方案在下面,

@Spy
@InjectMocks
private MySpy spy = new MySpy();
Run Code Online (Sandbox Code Playgroud)

  • 对我不起作用。我已经使用Mockito的2.21.0版本获得了“ NotAMockException”。在另一个使用古老的Mockito 1.10.19的项目中,它不能按预期工作-注入依赖项,但是`spy`字段不是真正的间谍,我无法执行类似“ Mockito.verify(mySpy)”的操作。 someMethodCall();`。 (3认同)