所以我开始为Java-Spring项目编写测试。
我使用的是JUnit和Mockito。它说,当我使用when()... thenReturn()选项时,我可以模拟服务,而不需要模拟它们。所以我想做的是,设置:
s = new Student();
s.constructor // returns function Person(){}
但无论我在哪个when子句中,我总是得到一个NullpointerException,当然这是有道理的,因为输入是null。
当我尝试从对象模拟另一个方法时:
s.constructor which is s.prototype.constructor would show function Person(){}
在那里我也得到一个Nullpointer,因为该方法需要一个不设置的变量。
但我想使用when().. thenReturn()来绕过创建这个变量等等。我只是想确保,如果任何类调用此方法,那么无论如何,只返回true或上面的列表。
这是我身边的一个基本误解,还是有其他错误?
代码:
when(classIwantToTest.object.get().methodWhichReturnsAList(input))thenReturn(ListcreatedInsideTheTestClass)
这是我的测试课:
when(object.method()).thenReturn(true)
答案 0 :(得分:78)
我遇到了这个问题,我的问题是我使用any()
而不是anyInt()
来调用我的方法。所以我有:
doAnswer(...).with(myMockObject).thisFuncTakesAnInt(any())
我必须将其更改为:
doAnswer(...).with(myMockObject).thisFuncTakesAnInt(anyInt())
我不知道为什么会产生NullPointerException。也许这会帮助下一个可怜的灵魂。
答案 1 :(得分:39)
对于布尔方法,尚未存根的方法的默认返回值为false
,返回集合或映射的方法为空集合或映射,否则为null
。
这也适用于when(...)
内的方法调用。在您的示例中,when(myService.getListWithData(inputData).get())
将导致NullPointerException,因为myService.getListWithData(inputData)
是null
- 它之前没有被存根。
一个选项是为所有中间返回值创建模拟,并在使用前将它们存根。例如:
ListWithData listWithData = mock(ListWithData.class);
when(listWithData.get()).thenReturn(item1);
when(myService.getListWithData()).thenReturn(listWithData);
或者,您可以在创建模拟时指定其他默认答案,以使方法返回新模拟而不是null:RETURNS_DEEP_STUBS
SomeService myService = mock(SomeService.class, Mockito.RETURNS_DEEP_STUBS);
when(myService.getListWithData().get()).thenReturn(item1);
您应该阅读Mockito.RETURNS_DEEP_STUBS的Javadoc,它会更详细地解释这一点,并且还会对其使用提出一些警告。
我希望这会有所帮助。请注意,您的示例代码似乎有更多问题,例如缺少断言或验证语句以及在模拟上调用setter(这没有任何影响)。
答案 2 :(得分:32)
我有同样的问题,我的问题只是我没有使用@RunWith正确注释该类。在您的示例中,请确保您具有:
@RunWith(MockitoJUnitRunner.class)
public class Test {
...
一旦我这样做,NullPointerExceptions就消失了。
答案 3 :(得分:7)
请确保您初始化了模拟程序。
JUnit4
使用@Before
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
}
JUnit5
使用@BeforeEach
@BeforeEach
public void setup() {
MockitoAnnotations.initMocks(this);
}
对于JUnit5
检查,您还使用了正确的导入。
import org.junit.runner.RunWith
import org.mockito.junit.MockitoJUnitRunner;
@RunWith(MockitoJUnitRunner.class)
答案 4 :(得分:5)
对我而言,我获得NPE的原因是我在模拟基元时使用Mockito.any()
。我发现通过切换到使用mockito的正确变体可以摆脱错误。
例如,要模拟一个将原始long
作为参数的函数,而不是使用any()
,您应该更具体,并将其替换为any(Long.class)
或{{1} }。
希望能有所帮助。
答案 5 :(得分:3)
转角案例
如果您正在使用 Scala 并尝试在值类上创建any
匹配器,那么您将获得无用的NPE。< / p>
所以给定case class ValueClass(value: Int) extends AnyVal
,你要做的是ValueClass(anyInt)
而不是any[ValueClass]
when(mock.someMethod(ValueClass(anyInt))).thenAnswer {
...
val v = ValueClass(invocation.getArguments()(0).asInstanceOf[Int])
...
}
其他SO question更具体地说明了这一点,但是当你不知道问题与价值等级有关时,你会错过它。
答案 6 :(得分:2)
对于将来的读者而言,使用模拟时导致NPE的另一个原因是忘记像这样初始化模拟:
@Mock
SomeMock someMock;
@InjectMocks
SomeService someService;
@Before
public void setup(){
MockitoAnnotations.initMocks(this); //without this you will get NPE
}
@Test
public void someTest(){
Mockito.when(someMock.someMethod()).thenReturn("some result");
// ...
}
答案 7 :(得分:1)
@RunWith(MockitoJUnitRunner.class) //(OR) PowerMockRunner.class
@PrepareForTest({UpdateUtil.class,Log.class,SharedPreferences.class,SharedPreferences.Editor.class})
public class InstallationTest extends TestCase{
@Mock
Context mockContext;
@Mock
SharedPreferences mSharedPreferences;
@Mock
SharedPreferences.Editor mSharedPreferenceEdtor;
@Before
public void setUp() throws Exception
{
// mockContext = Mockito.mock(Context.class);
// mSharedPreferences = Mockito.mock(SharedPreferences.class);
// mSharedPreferenceEdtor = Mockito.mock(SharedPreferences.Editor.class);
when(mockContext.getSharedPreferences(Mockito.anyString(),Mockito.anyInt())).thenReturn(mSharedPreferences);
when(mSharedPreferences.edit()).thenReturn(mSharedPreferenceEdtor);
when(mSharedPreferenceEdtor.remove(Mockito.anyString())).thenReturn(mSharedPreferenceEdtor);
when(mSharedPreferenceEdtor.putString(Mockito.anyString(),Mockito.anyString())).thenReturn(mSharedPreferenceEdtor);
}
@Test
public void deletePreferencesTest() throws Exception {
}
}
以上所有评论代码均不是必需的
{mockContext = Mockito.mock(Context.class);
},
如果您使用 @Mock 注释到Context mockContext;
@Mock
Context mockContext;
但是如果你只使用 @RunWith(MockitoJUnitRunner.class)它会有效。根据Mockito,您可以使用 @Mock或Mockito.mock(Context.class)创建模拟对象; ,
由于使用了@RunWith(PowerMockRunner.class),我得到了NullpointerException,而不是我改为@RunWith(MockitoJUnitRunner.class),它运行良好
答案 8 :(得分:1)
对于 JUnit 5,测试类必须注解:
@ExtendWith(MockitoExtension.class)
进口:
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.junit.jupiter.MockitoExtension;
这个添加解决了我的问题。
答案 9 :(得分:1)
您需要初始化MockitoAnnotations.initMocks(this)方法必须调用以初始化带注释的字段。
@Before public void initMocks() {
MockitoAnnotations.initMocks(this);
}
有关更多详细信息,请参见Doc
答案 10 :(得分:0)
在我的情况下,这是因为错误的注释使用。我使用 junit 4 进行测试并在初始化时使用 @BeforeEach
而不是 @Before
。
将其更改为 @Before
,它的作用就像魅力一样。
答案 11 :(得分:0)
对我来说,这是因为我在 @BeforeAll
方法中存根了模拟。
MockitoExtension
没有 @BeforeAll
的回调。
public class MockitoExtension implements BeforeEachCallback, AfterEachCallback, ParameterResolver
我将存根移到了它工作的测试方法中!!
答案 12 :(得分:0)
使用 @ExtendWith(MockitoExtension.class)
注释测试类。
答案 13 :(得分:0)
在我的情况下,这是由于@Test注释的导入错误
确保您正在使用以下导入
import org.junit.jupiter.api.Test;
答案 14 :(得分:0)
由于这是我发现的与问题最接近的结果,因此是第一个结果,但我没有找到合适的答案,因此我将在此处发布解决方案,以解决将来任何可怜的人:
any()
在模拟类方法使用原始参数的情况下不起作用。
public Boolean getResult(String identifier, boolean switch)
以上内容将产生与OP完全相同的问题。
解决方案,只需将其包装:
public Boolean getResult(String identifier, Boolean switch)
后者解决了NPE。
答案 15 :(得分:0)
另一个常见的陷阱是方法签名被意外声明为“最终”。
这个人吸引了很多使用Checkstyle进行代码库开发的人员,并且内部化了将成员标记为final
的需要。
即在OP的示例中:
object.method()
确保未将method()
声明为final
:
public final Object method() {
}
Mockito无法模拟最终方法,它将作为包装的NPE出现:
Suppressed: org.mockito.exceptions.misusing.InvalidUseOfMatchersException:
在错误消息中深入了解以下内容:
Also, this error might show up because you use argument matchers with methods that cannot be mocked.
Following methods *cannot* be stubbed/verified: final/private/equals()/hashCode().
Mocking methods declared on non-public parent classes is not supported.
答案 16 :(得分:0)
使用JUnit 5或更高版本时。您必须注入用@Mock
注释的类
在@BeforeEach
设置中。
答案 17 :(得分:0)
以上答案均无济于事。我在努力理解为什么代码可以在Java中工作而在Kotlin中不能工作。
然后我从this thread中找出了答案。
您必须创建类和成员函数open
,否则将引发NPE。
完成功能open
后,测试开始通过。
您最好考虑使用编译器的"all-open" plugin:
Kotlin具有类及其成员,默认情况下为 final ,这使得使用Spring AOP等要求类开放<的框架和库变得不方便/ strong>。
all-open
编译器插件使Kotlin适应了这些框架的要求,并使带有特定注释的类被注释,并且其成员打开而没有明确的open关键字。
答案 18 :(得分:0)
这些答案都不对我有用。这个答案不能解决OP的问题,但是由于这篇文章是唯一出现在Google搜索此问题的文章,所以我在这里分享我的答案。
在编写Android单元测试时遇到了这个问题。问题是我正在测试的活动扩展了AppCompatActivity
而不是Activity
。为了解决这个问题,我可以将AppCompatActivity
替换为Activity
,因为我并不是真的需要它。这可能不是每个人都可行的解决方案,但希望知道根本原因会有所帮助。
答案 19 :(得分:0)
就我而言,我错过了先添加
PowerMockito.spy(ClassWhichNeedToBeStaticMocked.class);
所以这对看到这种错误的人很有帮助
java.lang.NullPointerException
at org.powermock.api.mockito.internal.expectation.PowerMockitoStubberImpl.addAnswersForStubbing(PowerMockitoStubberImpl.java:67)
at org.powermock.api.mockito.internal.expectation.PowerMockitoStubberImpl.when(PowerMockitoStubberImpl.java:42)
at org.powermock.api.mockito.internal.expectation.PowerMockitoStubberImpl.when(PowerMockitoStubberImpl.java:112)
答案 20 :(得分:0)
答案 21 :(得分:0)
面临同样的问题,这个解决方案对我有用:
我使用@InjectMocks来模拟服务实现,而不是模拟服务接口:
@InjectMocks
private exampleServiceImpl exampleServiceMock;
而不是:
@Mock
private exampleService exampleServiceMock;