Mockito将模拟注入Spy对象

时间:2017-05-11 22:34:00

标签: 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
    }

}

5 个答案:

答案 0 :(得分:16)

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

以下方法将工作:

@Spy
@InjectMocks
private MySpy spy;

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

@Mock
private NeedToBeMocked needToBeMocked;

@InjectMocks
private MySpy mySpy;

@InjectMocks
private SubjectUnderTest sut;

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

SubjectUnderTest此处取决于MySpyMySpy依赖于NeedToBeMocked)。

UPD:就个人而言,我认为如果你不得不经常做这样的魔术,这可能表明你的课程之间的依赖关系有问题,并且值得执行一个一点点重构,以改善您的代码。

答案 1 :(得分:11)

最适合我的解决方案。

@InjectMocks
private MySpy spy = Mockito.spy(new MySpy());

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

答案 2 :(得分:9)

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;
    }
}

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

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();
    }

}

答案 3 :(得分:6)

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

Yorory N的先前答案。

@Spy
@InjectMocks
private MySpy spy;

因为需要创建InjectMocks实例,所以下面的解决方案对我有用

@Spy
@InjectMocks
private MySpy spy = new MySpy();

答案 4 :(得分:1)

我想我刚刚找到了明确的答案。我尝试了Yoory方法,但更改了注释的顺序:

@InjectMocks
@Spy
private MySpy spy;

我假设Mockito首先创建了模拟,然后在其上添加了一个间谍。因此,无需实例化MySpy对象。

相关问题