当我使用@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.
答案 0 :(得分:2)
这个例子告诉你什么......
您尚未在字段声明中提供实例
换句话说,你没有写......
@InjectMocks
A a = new A("foobar", 123);
这是完全可以接受的,可能会解决您的问题。请记住,那时嘲笑不会被初始化,所以如果你真的需要一个例子String
和int
,那就好了,但如果你需要在那里放置嘲笑则不行。换句话说,如果你有一个带X的构造函数,你会在这里编写新的A(x)
,那么x将为null,因为@Mock
注释还没有被处理过。
所以我试着构建实例
因为没有实例(因为你没有提供),所以它试图创建一个实例,但是......
但是,构造函数或初始化块引发了异常:null
因此,您的构造函数抛出null。看起来你的someMethodCall
依赖于参数(端口,最有可能),因为它们是String
和int
,因此Mockito不知道在那里使用什么值。由于port
是一种原始类型而Mockito没有专门处理这些问题,因此可能存在问题--Mockito会尝试将null置于那里,这将引发异常。
如果你的构造函数匹配X和Y,例如,Mockito可能会尝试将模拟放在那里,但它没有。构造函数需要String
和int
,并且没有针对它们的模拟,因此Mockito只能使用默认值,而null
是port
的问题(因为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);
}