@InjectMocks 后为空

问题描述 投票:0回答:7

在使用 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的真正实现,最终返回所需的值。

另一种选择是使用真实的 FastPowering 实例

https://github.com/mockito/mockito/wiki/Using-Spies-(and-Fakes) https://github.com/mockito/mockito/wiki/Mocking-Object-Creation

一些 stackoverflow 线程概述了差异 模拟框架中的模拟与间谍活动

简短回答:将

@Mock
替换为
@Spy
并且应该可以正常工作

java null mocking mockito inject
7个回答
34
投票

使用

MockitoAnnotations.initMocks
启动
@Mock
@InjectMocks
对象。您的测试将类似于:

@Mock
FastPowering fastPower;

@InjectMocks
Controller controller;

@Before
public void setup() {
    MockitoAnnotations.initMocks(this);
}

@Test
public void test() {
    ....
}

6
投票

我使用了错误的

@Test
注释,如果你想在 Mockito 测试中使用
@InjectMocks
@Mock
,那么你应该

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

这适用于

mockito-core:3.6.28


4
投票

调试后找到了原因。这是因为

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)
方法,它不会影响结果。


3
投票

我通过删除在 @Before 方法中创建的无关新实例来修复此问题(请参见下面的示例)。也可以通过在初始化

MockitoAnnotations.initMocks(this)
后移动
myClass
来修复该问题,但由于 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
}

2
投票

值得注意的是,

MockitoAnnotations.initMocks(this);
的使用需要出现在@Before/
setUp()
方法的
end

如果它位于

setUp()
的顶部,那么可能会导致其他模拟类无法初始化。

我自己刚刚遇到了这个错误,并将

.initMocks
放在我的
@Before
的末尾解决了我的问题。


0
投票

我想提一件事要检查,发生在我身上的是我调用了错误的注入对象,或者更确切地说,我调用了父类,我应该在其中调用子类,这是我注入的模拟对象中的子类.


-1
投票

还有 2 件事需要检查:

1. Mocking the behaviours of fastPower. What should this mocked object return, when it methods are called? i.e. when(fastPower.doSomething()).thenReturn(some_kind_of_object);
2. Check if the controller.computeAnswer() does not return NULL for the input of new BigDecimal(2), 2)).longValue(), (long) Math.pow(2, 2).
© www.soinside.com 2019 - 2024. All rights reserved.