Null after @InjectMocks



在使用 JUnit 进行单元测试时,我在传递依赖项时遇到了一些麻烦。

请考虑以下代码段:

这是我要测试的类中的依赖注入,我们称之为控制器。

@Inject private FastPowering fastPowering;  

这是单元测试:

@RunWith(MockitoJUnitRunner.class)
public class ControllerTest {
@Mock
FastPowering fastPower;
@InjectMocks
Controller controller;
@Test
public void test() {
    assertEquals(
            (controller.computeAnswer(new BigDecimal(2), 2)).longValue(),
            (long) Math.pow(2, 2));
    }
}

似乎 fastPower 为空,请解释如何解决。空指针异常,因为在 .computeAnswer 方法中调用@injected字段 (fastPower)

编辑:

解决了我应该读过@Mock和@Spy之间的区别......

由于有很多评论,我正在为解决方案添加更多上下文

不同之处在于,在模拟中,您

正在创建一个完整的模拟或假对象,而在间谍中,有真正的对象,您只是监视或存根它的特定方法。当然,在间谍对象中,由于它是一个真正的方法,当你不存根该方法时,那么它将调用真正的方法行为。

如果fastPower被注释为@Mock那么它的方法就是虚拟的,但controller.computeAnswer依赖于它们来计算。一个人必须提供行为。

如果在没有存根的情况下使用间谍,那么正在执行 fastPower 的真正实现,最终返回所需的值。

另一种选择是使用真正的快速供电实例

https://github.com/mockito/mockito/wiki/Using-间谍-(和假货)https://github.com/mockito/mockito/wiki/Mocking-Object-Creation

还有一些堆栈溢出线程概述了模拟框架中的模拟与间谍的区别

简短回答:将@Mock替换为@Spy,应该工作正常

使用 MockitoAnnotations.initMocks 启动@Mock@InjectMocks对象。您的测试将如下所示:

@Mock
FastPowering fastPower;
@InjectMocks
Controller controller;
@Before
public void setup() {
    MockitoAnnotations.initMocks(this);
}
@Test
public void test() {
    ....
}

我使用了错误的@Test注释,如果您想在 Mockito 测试中使用 @InjectMocks@Mock,那么您应该

  1. 在测试类上添加@ExtendWith(MockitoExtension.class)注释
  2. 使用@Test (org.junit.jupiter.api.Test)而不是@Test (org.junit.Test)注释来批注测试方法。 请小心用于此批注的导入。

这适用于mockito-core:3.6.28

调试后我找到了一个原因。这是因为org.powermock.core.MockRepository#instanceMocks收藏。它不包含带有@InjectMocks注释的字段的模拟(在您的情况下Controller controller)。要解决这个问题,请尝试在字段声明中使用@Spy注释,并初始化它们并在类声明上方@PrepareForTest

@PrepareForTest(Controller.class)
@RunWith(MockitoJUnitRunner.class)
public class ControllerTest {
    
    @Mock
    FastPowering fastPower;
    
    @Spy
    @InjectMocks    
    Controller controller = new Controller();
    
    @Test
    public void test() {
        //...
    }
}

就我而言,它有所帮助。不需要使用 Mockitoannotations.initMocks(this) 方法,它不会影响结果。

我通过删除我在 @Before 方法中创建的无关新实例来解决此问题(请参阅下面的示例)。它也通过在初始化myClass后移动MockitoAnnotations.initMocks(this)来修复,但由于 Mockito 无论如何都创建了myClass,因此该解决方案较差。

// Note - you may need @mock(name="foo") to help mockito differentiate props
//        if they have the same type
@Mock
private Thing something;
@InjectMocks
private MyClass myClass;
@Before
 public void setUp() {
    MockitoAnnotations.initMocks(this); // Moving this below the next line fixed it...
    myClass = new MyClass() // But just remove this line and let Mockito do the work
}

需要注意的是,MockitoAnnotations.initMocks(this);的使用需要在@Before/setUp()方法结束时使用。

如果它位于setUp()的顶部,则可能导致其他模拟类无法初始化。

我自己刚刚遇到了这个错误,.initMocks放在@Before的末尾解决了我的问题。

还有 2 件事要检查:

  1. 嘲笑快力的行为。调用此方法时,此模拟对象应返回什么?即 when(fastPower.doSomething()).thenReturn(some_kind_of_object);
  2. 检查 controller.computeAnswer() 是否没有为新的 BigDecimal(2), 2) 的输入返回 NULL)。longValue(), (long) Math.pow(2, 2).

相关内容

  • 没有找到相关文章

最新更新