存根方法时的 Mockito-NullpointerException

因此,我开始为我们的 Java-Spring 项目编写测试。

我使用的是 JUnit 和 Mockito。据说,当我使用 when () ... then Return ()选项时,我可以模拟服务,而不用模拟它们。所以我想做的是,设置:

when(classIwantToTest.object.get().methodWhichReturnsAList(input))thenReturn(ListcreatedInsideTheTestClass)

但是,无论我使用哪个 when 子句,我总是会得到一个 NullpointerException,这当然是有意义的,因为 input 是 null。

同样,当我试图从一个对象模仿另一个方法时:

when(object.method()).thenReturn(true)

在那里我还得到了一个 Nullpoint,因为这个方法需要一个变量,而这个变量是没有设置的。

但我想用 when ()。.然后使用 return ()来创建这个变量等等。我只是想确保,如果有类调用这个方法,那么无论如何,只要返回 true 或者上面的列表。

这是我这边的误会,还是有什么别的问题?

密码:

public class classIWantToTest implements classIWantToTestFacade{
@Autowired
private SomeService myService;


@Override
public Optional<OutputData> getInformations(final InputData inputData) {
final Optional<OutputData> data = myService.getListWithData(inputData);
if (data.isPresent()) {
final List<ItemData> allData = data.get().getItemDatas();
//do something with the data and allData
return data;
}


return Optional.absent();
}
}

这是我的测试课:

public class Test {


private InputData inputdata;


private ClassUnderTest classUnderTest;


final List<ItemData> allData = new ArrayList<ItemData>();


@Mock
private DeliveryItemData item1;


@Mock
private DeliveryItemData item2;






@Mock
private SomeService myService;




@Before
public void setUp() throws Exception {
classUnderTest = new ClassUnderTest();
myService = mock(myService.class);
classUnderTest.setService(myService);
item1 = mock(DeliveryItemData.class);
item2 = mock(DeliveryItemData.class);


}




@Test
public void test_sort() {
createData();
when(myService.getListWithData(inputdata).get().getItemDatas());


when(item1.hasSomething()).thenReturn(true);
when(item2.hasSomething()).thenReturn(false);


}


public void createData() {
item1.setSomeValue("val");
item2.setSomeOtherValue("test");


item2.setSomeValue("val");
item2.setSomeOtherValue("value");


allData.add(item1);
allData.add(item2);




}
310997 次浏览

尚未存根的方法的默认返回值是布尔方法的 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 (这没有任何效果)。

我也有同样的问题,问题很简单,我没有使用@RunWith 对类进行正确的注释。在你的例子中,确保你有:

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

这样做之后,NullPointerException 就消失了。

我有这个问题,我的问题是我正在用 any()而不是 anyInt()调用我的方法。所以我想:

doAnswer(...).with(myMockObject).thisFuncTakesAnInt(any())

我不得不改成:

doAnswer(...).with(myMockObject).thisFuncTakesAnInt(anyInt())

我不知道为什么会产生 NullPointerException。也许这会帮助下一个可怜的灵魂。

@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);}, 如果使用 @ 嘲笑注释到 Context mockContext;

@Mock
Context mockContext;

但是,如果您只使用 @ RunWith (MockitoJUnitRunner.class),它将工作。根据 Mockito,您可以使用 @ Mock 或 Mockito.mock (Context.class) ;创建模拟对象,

因为使用了@RunWith (PowerMockRunner.class) ,我得到了 NullpointerException,而不是我改为@RunWith (MockitoJUnitRunner.class) ,它工作得很好

角落案例:
如果您正在使用 斯卡拉并试图在 价值等级上创建一个 any匹配器,那么您将得到一个无用的 NPE。

给定 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])
...
}

另一个 有个问题更具体地讲述了这个问题,但是当您不知道值类的问题时,您就会错过它。

对我来说,获得 NPE 的原因是我在模仿原语时使用了 Mockito.any()。我发现,通过切换到使用正确的变体从仿音摆脱了错误。

例如,要模拟一个以基元 long作为参数的函数,而不是使用 any(),您应该更具体一些,并将其替换为 any(Long.class)Mockito.anyLong()

希望这对某人有帮助。

对于未来的读者,使用模拟时 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");
// ...
}

还要确保所有注释都使用 JUnit。 我曾经偶然地使用 testNG 中的@Test 创建了一个测试,所以@Before 不能使用它(在 testNG 中,注释是@Before Test)

Ed Webb 的 回答对我的情况很有帮助,你也可以试试 add

  @Rule public Mocks mocks = new Mocks(this);

如果你 @RunWith(JUnit4.class)

对我来说,我错过了加法

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)

这些答案对我都不管用。这个答案并不能解决 OP 的问题,但是因为这篇文章是唯一一个出现在谷歌上的问题,我在这里分享我的答案。

我在为 Android 编写单元测试时遇到了这个问题。问题是我测试的活动扩展了 AppCompatActivity而不是 Activity。为了解决这个问题,我只能用 Activity代替 AppCompatActivity,因为我并不真正需要它。对于每个人来说,这可能不是一个可行的解决方案,但是希望知道根本原因会对某些人有所帮助。

以上的答案对我都没有帮助。我一直在努力理解为什么代码在 Java 中可以工作,而在 Kotlin 却可以工作。

然后我从 这根线上看出来了。

必须创建类和成员函数 open,否则将引发 NPE。

功能完成后,open测试开始通过。

你不妨考虑使用编译器的 “全开”插件:

Kotlin 有类及其成员 默认情况下为 final,这使得使用框架和类库(如 Spring AOP)变得不方便,因为这些框架和类库要求类为 打开all-open编译器插件使 Kotlin 适应这些框架和 使用特定的注释对类进行注释,并打开它们的成员的要求,而没有显式的 open 关键字。

您需要初始化 MockitoAnnotations.initMocks (this)方法来初始化带注释的字段。

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

详情请参阅 医生

当使用 JUnit5或更高版本时,必须注入带有 @Mock注释的类 在 @BeforeEach设置中。

确保初始化了模拟。

使用 @Before

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

使用 @BeforeEach

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

对于 JUnit5检查,您也正在使用适当的导入。

import org.junit.runner.RunWith
import org.mockito.junit.MockitoJUnitRunner;


@RunWith(MockitoJUnitRunner.class)

另一个常见的问题是,方法签名意外地被声明为“ final”。

这篇文章抓住了许多从事代码库工作的人,这些代码库受制于 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.

由于这是我发现的最接近我所遇到的问题的结果,这是第一个出现的结果,我没有找到一个合适的答案,我将在这里为任何未来可怜的灵魂提供解决方案:

如果模拟类方法使用基元参数,则 any()不起作用。

 public Boolean getResult(String identifier, boolean switch)

以上将产生与 OP 完全相同的问题。

解决方案,只要包装它:

 public Boolean getResult(String identifier, Boolean switch)

后者解决 NPE。

  • 如果您选择了这种方法,请记住,现在您可能需要在生产代码 中包含一个布尔值的空检查(Credit: up by Ridcully)

在我的例子中,这是由于@Test 注释的错误导入造成的

确保您正在使用以下导入

import org.junit.jupiter.api.Test;

对于 JUnit 5,测试类必须注释以下内容:

@ExtendWith(MockitoExtension.class)

进口:

import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.junit.jupiter.MockitoExtension;

我的问题已经解决了。

用: @ExtendWith(MockitoExtension.class)注释测试类。

对我来说,这是因为我在 @BeforeAll方法中使用了 mock。

MockitoExtension没有 @BeforeAll的回调。

public class MockitoExtension implements BeforeEachCallback, AfterEachCallback, ParameterResolver

我移动了测试方法里面的存根,它起作用了! !

在我的例子中,这是因为错误的注释用法。我使用 junit4进行测试,并在初始化时使用 @BeforeEach而不是 @Before

把它改成 @Before,效果非常好。

在我的案例中,它是 when()的错误导入。

我不小心用了 import static reactor.core.publisher.Mono.when

在我的例子中,缺少 mapper 声明中的注释 @mock

在我的例子中,Intellij 使用 org.junit.jupiter.api.Test(Junit5)而不是导入 org.junit.Test(Junit4)来创建 Test,这显然导致所有 bean 为 null。 还要确保类和测试方法是公共的

这是谷歌带我时,我有相同的 NullPointerException与 Junit5,但正确地使用 @ExtendWith(MockitoExtension.class)在我的 maven 项目。

原来我没有在 pom.xml 中包含 maven-surefire-plugin,这意味着 @ExtendWith实际上没有做任何事情!

<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.1</version>
</plugin>
...

在我的例子中,一个被测试的方法调用另一个方法作为参数:

Mockito.`when`(repository.getItems(prefs.getUser().id)).thenReturn(listOf())`

当模拟 repository时,prefs.getUser().id)将抛出 NPE。因此,首先我们应该模拟一个参数,例如,

Mockito.`when`(prefs.getUser()).thenReturn(User(id = 1, name = "user"))`

我们也应该嘲笑 prefs。我没有检查它,并改变了一个库,对不起。

我试图嘲笑一个“最终”的方法,这显然就是问题所在。

处理这个问题的正确方法是使用一个接口并模拟该接口,但是我不能控制“ final”方法所在的库。

Mockito 2可以处理 Mockito 的最终方法。将一个文本文件添加到项目的 src/test/resources/挖掘扩展目录中,该目录名为 org.modito.plugins。MockMaker 并添加一行文本:

mock-maker-inline

在此之后,模仿最终方法应该就可以了。

检查您使用的是哪个版本的 Junit。在 Maven/Gradle 构建工具中,如果您设置使用 testRuntimeOnly 'junit5',那么它可能不采用 @RunWith,因为它不可用,并且在 Junit5中用 @ExtendWith替换。

这并没有回答 OP 的原始查询,但是它在这里尝试用 Mockito 空指针异常(NPE)帮助其他人。

我的 NPE 正在发生,因为我没有显式地将测试依赖项下的类设置为我模拟的类。因此,被测试的类无法找到它所需的依赖项,从而创建了 NPE。我倾向于不模仿测试中的类(即使用 new关键字) ,以确保我得到测试的本机类行为。

出于我无法控制的原因,我仍然在使用 JUnit 4

ClassUnderTest

public class ClassUnderTest {
private DependantClassOne dependantClassOne;
private DependantClassTwo dependantClassTwo;


// remaining class, including setters
}

测试班

@RunWith(MockitoJUnitRunner.class)
public class Test {
private ClassUnderTest classUnderTest;
private DependantClassOne dependantClassOne;
private DependantClassTwo dependantClassTwo;
 

@Before
public void setup() {
dependantClassOne = mock(DependantClassOne.class);
dependantClassTwo = mock(DependantClassTwo.class);
classUnderTest = new ClassUnderTest();


classUnderTest.setDependantClassOne(dependantClassOne); //added to prevent NPE
classUnderTest.setDependantClassTwo(dependantClassTwo); //added to prevent NPE
}


// tests
}

在我的例子中,我的 Mockito 注释与 JUnit 版本不匹配。

  1. 在使用 @ExtendWith(MockitoExtension.class)时,请确保使用的是 JUnit5: import org.junit.jupiter.api.Test;

  2. 在使用 @RunWith(MockitoJUnitRunner.class)时,请确保使用的是 JUnit4: import org.junit.Test;