mockito 在@注入模拟后为空

bnlyeluc  于 2022-11-08  发布在  其他
关注(0)|答案(6)|浏览(495)

在使用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似乎为空,请解释如何修复. Null指针异常,因为在.computeAnswer方法中调用@injected字段(fastPower))
编辑:
解决了我应该读到@Mock和@Spy之间的区别...
由于有很多评论,我将为解决方案添加更多上下文
不同的是,在mock中,你创建的是一个完整的mock或fake对象,而在spy中,有一个真正的对象,你只是窥探或存根它的特定方法。而在spy对象中,当然,由于它是一个真正的方法,当你不存根该方法时,它将调用真正的方法行为。
如果fastPower被标注为 @Mock,它的方法是虚拟的,但是 controller.computeAnswer 依赖于它们来计算。必须提供行为。
如果使用spy而不使用存根,则会执行 fastPower 的实际实现,最终返回所需的值。
另一种选择是使用真实的 FastPowering 示例
https://github.com/mockito/mockito/wiki/Using-Spies-(and-Fakes)https://github.com/mockito/mockito/wiki/Mocking-Object-Creation显示器
一些堆栈溢出线程概述了Mocking vs. Spying in mocking frameworks的不同之处。
简短回答:将@Mock替换为@Spy,应该可以正常工作

a11xaf1n

a11xaf1n1#

使用MockitoAnnotations.initMocks来初始化@Mock@InjectMocks对象。您的测试看起来会像这样:

@Mock
FastPowering fastPower;

@InjectMocks
Controller controller;

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

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

omtl5h9j2#

我通过删除我在@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
}
h7wcgrx3

h7wcgrx33#

调试后我发现了一个原因。这是因为集合org.powermock.core.MockRepository#instanceMocks不包含一个带有@InjectMocks注解的字段的mock(在您的例子中是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)不是必需的,它不会影响结果。

llew8vvj

llew8vvj4#

需要注意的是,MockitoAnnotations.initMocks(this);的使用需要在@Before/setUp()方法的结尾出现。
如果它在setUp()的顶部,那么它可能会导致其他模拟类无法初始化。
我刚才自己也遇到了这个错误,把.initMocks放在我的@Before的末尾解决了我的问题。

qncylg1j

qncylg1j5#

我使用了错误的@Test注解,如果您想在Mockito测试中使用@InjectMocks@Mock,那么您应该
1.在测试类上添加@ExtendWith(MockitoExtension.class)注解
1.使用@Test (org.junit.jupiter.api.Test)而不是@Test (org.junit.Test)注解来注解您的测试方法。请小心使用您用于此注解的导入。
这适用于mockito-core:3.6.28

guicsvcw

guicsvcw6#

还有两件事要检查:

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).

相关问题