@InjectMocks,构造函数或初始化块引发了异常

时间:2017-11-24 02:35:06

标签: junit mockito

当我使用@InjectMocks时,发生了异常。我的代码如下所示:

class A {
    private X x;
    private Y y;
    public A(String ip, int port) {
       this(someMethodCall(ip, port)); //
    }

    private A(X x) {
        this.x = x;
        this.y = new Y();
    }
}
UT:
public class ATest() {
    @InjectMocks A a;
    @Mock X x;
    @Mock Y y;
    @Test ...
}

它会抛出NPE,有人可以帮助我吗?

org.mockito.exceptions.base.MockitoException: Cannot instantiate @InjectMocks field named 'channel' of type 'class Juinit3.Channel'. You haven't provided the instance at field declaration so I tried to construct the instance. However, the constructor or the initialization block threw an exception: null.

3 个答案:

答案 0 :(得分:2)

这个例子告诉你什么......

  

您尚未在字段声明中提供实例

换句话说,你没有写......

@InjectMocks 
A a = new A("foobar", 123);

这是完全可以接受的,可能会解决您的问题。请记住,那时嘲笑不会被初始化,所以如果你真的需要一个例子Stringint,那就好了,但如果你需要在那里放置嘲笑则不行。换句话说,如果你有一个带X的构造函数,你会在这里编写新的A(x),那么x将为null,因为@Mock注释还没有被处理过。

  

所以我试着构建实例

因为没有实例(因为你没有提供),所以它试图创建一个实例,但是......

  

但是,构造函数或初始化块引发了异常:null

因此,您的构造函数抛出null。看起来你的someMethodCall依赖于参数(端口,最有可能),因为它们是Stringint,因此Mockito不知道在那里使用什么值。由于port是一种原始类型而Mockito没有专门处理这些问题,因此可能存在问题--Mockito会尝试将null置于那里,这将引发异常。

如果你的构造函数匹配X和Y,例如,Mockito可能会尝试将模拟放在那里,但它没有。构造函数需要Stringint,并且没有针对它们的模拟,因此Mockito只能使用默认值,而nullport的问题(因为int)。

那么,解决方案是什么?

1)使构造函数为null安全,允许在那里给出一个null-port(并确保ip字符串也以null安全的方式处理)。

2)使用你没用过的东西:

@InjectMocks 
A a = new A("foobar", 123);

在任何情况下,都不需要在构造函数中包含所有依赖项,Mockito会将它们直接注入字段。因此,为X和Y添加另一个构造函数不是一个真正的解决方案。当然,通常情况下,构造函数注入优于场注入,但这是另一个主题。

至于你关于哪个构造函数的问题:documentation说明了这个......

  

选择了最大的构造函数,然后使用仅在测试中声明的模拟来解析参数

编辑:似乎Mockito不知道如何处理构造函数中的原始字段,真可惜。

答案 1 :(得分:2)

问题在于您的@InjectMocks字段。因为你没有像这样直接初始化它:

@InjectMocks A a = new A("localhost", 80);

mockito将尝试进行构造函数初始化。在这种情况下,它将选择最大的构造函数。在你的情况下它是public A(String ip, int port)。如果没有提供的模拟字段与构造函数参数匹配,则mockito将传递null s作为选择构造函数的值。因此,在这种情况下,实例初始化为new A(null, null)。在这种情况下,您将获得NPE,因为构造函数的第二个参数是int,而null将被取消装箱到int {{1}将被抛出。

答案 2 :(得分:0)

1)创建公共非args构造函数或创建public A(X x, Y y)构造函数。

2)确保使用

@RunWith(MockitoJUnitRunner.class)
public class ATest() {

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