繁体   English   中英

Mockito 将模拟注入间谍 object

[英]Mockito Inject mock into Spy object

我正在为 Class 编写一个测试用例,它具有 2 级依赖注入。 我对 1 级依赖注入 object 使用 @Spy 注释,我想模拟第二级注入。 但是,我一直在第 2 级得到 null 指针异常。 有什么办法可以将模拟注入 @Spy object?

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
    }

}

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

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

@Spy
@InjectMocks
private MySpy spy;

但是,当同时使用注释和手动模拟时,可以通过“混合”方法来实现所需的行为。 以下工作完美:

@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这里取决于MySpy ,并MySpy反过来取决于NeedToBeMocked )。

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

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

}

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

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

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

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

Yoory N 之前的回答

@Spy
@InjectMocks
private MySpy spy;

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

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

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

@InjectMocks
@Spy
private MySpy spy;

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

Junit5 + mockito-junit-upiter-4.2.0 运行良好

@ExtendWith(MockitoExtension.class)
public class MyTest {

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM