Mockito - NullpointerException when stubbing Method



所以我开始为我们的Java-Spring项目编写测试。

我使用的是JUnit和Mockito。据说,当我使用 when((...thenReturn(( 选项 我可以模拟服务,而无需模拟它们左右。所以我想做的是,设置:

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

但是无论我使用哪个 when-clause,我总是得到一个 NullpointerException,这当然是有意义的,因为输入是空的。

另外,当我尝试从对象模拟另一种方法时:

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

在那里,我还得到了一个 Nullpointer,因为该方法需要一个未设置的变量。

但我想使用 when((。thenReturn(( 来绕过创建这个变量等等。我只是想确保,如果任何类调用此方法,那么无论如何,只需返回 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);

}

我遇到了这个问题,我的问题是我用any()而不是anyInt()调用我的方法。 所以我有:

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

我不得不将其更改为:

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

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

尚未存根的方法的默认返回值对于布尔方法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);

您应该阅读 Javadoc of Mockito.RETURNS_DEEP_STUBS 它更详细地解释了这一点,并且还对其用法有一些警告。

我希望这有所帮助。请注意,您的示例代码似乎存在更多问题,例如缺少断言或验证语句以及在模拟上调用 setter(这没有任何影响(。

我遇到了同样的问题,我的问题只是我没有使用@RunWith正确注释类。在您的示例中,请确保您具有:

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

一旦我这样做了,NullPointerExceptions就消失了。

对于未来的读者来说,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中,注释是@BeforeTest(

对我来说

,我得到NPE的原因是我在嘲笑原语时使用Mockito.any()。我发现通过切换到使用mockito的正确变体可以摆脱错误。

例如,要模拟将原始long作为参数的函数,而不是使用 any() ,您应该更具体地将其替换为 any(Long.class)Mockito.anyLong()

希望对某人有所帮助。

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

any()在模拟类方法使用基元参数的情况下不起作用。

 public Boolean getResult(String identifier, boolean switch)

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

解决方案,只需包装它:

 public Boolean getResult(String identifier, Boolean switch)

后者解决了NPE。

  • Image caption 如果你选择这种方法,现在你可能希望在生产代码中包含布尔值的 nullcheck(图片来源:Ridcully 提出(

确保初始化模拟。

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)

极端情况:
如果您使用的是 Scala,并且尝试在值类上创建一个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])
   ...
}

另一个 SO 问题更具体地涉及这一点,但当您不知道问题出在值类上时,您会错过它。

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

@ExtendWith(MockitoExtension.class)

进口:

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

我的问题已通过此添加得到解决。

你需要

初始化MockitoAnnotations.initMocks(this(方法必须调用来初始化注释字段。

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

有关更多详细信息,请参阅文档

检查方法签名是否未声明为 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.

就我而言,我的 Mockito 注释与 JUnit 版本不匹配。

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

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

以上答案都没有帮助我。我一直在努力理解为什么代码在 Java 中有效,而在 Kotlin 中不起作用

然后我从这个线程中想通了。

你必须使类和成员函数open,否则NPE就会被抛出。

在制作功能后open测试开始通过。

您不妨考虑使用编译器的"全开放"插件:

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

对我来说

,这是因为我在@BeforeAll方法中存根模拟。

MockitoExtension没有@BeforeAll的回调。

public class MockitoExtension implements BeforeEachCallback, AfterEachCallback, ParameterResolver

我将存根移到测试方法内,它起作用了!!

就我而言,这是错误的导入when().

我偶然使用了import static reactor.core.publisher.Mono.when

就我而言,Intellij 创建了带有 org.junit.jupiter.api.Test (Junit5( 的 Test 而不是 (Junit4( 的导入org.junit.Test,这显然导致所有 bean 都是空的。另外,请确保类和测试方法是公共

就我而言,我错过了先添加

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)
@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(;

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

就我而言,这是因为错误的注释使用。我使用 junit 4 进行测试,并在初始化时使用 @BeforeEach 而不是 @Before

把它改成@Before,它就像魅力一样工作。

当我

与Junit 5有相同的NullPointerException时,这就是谷歌带我去的地方,但在我的maven项目中正确地使用了@ExtendWith(MockitoExtension.class)

事实证明,我没有将maven-surefire-plugin包含在我的pom中.xml这意味着@ExtendWith实际上什么也没做!

<build>
  <plugins>
    <plugin>
      <groupId>org.apache.maven.plugins</groupId>
      <artifactId>maven-surefire-plugin</artifactId>
      <version>2.22.1</version>
    </plugin>
    ...
<</div> div class="one_answers">

我使用了错误的 mock 注释/导入,所以我的对象没有形成。我正在使用org.evosuite.shaded.org.mockito.Mock,我切换回org.mockito.Mock.然后就像变魔术一样,它开始为我工作。

Ed Webb的回答对我的情况有所帮助。相反,您也可以尝试添加

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

如果你@RunWith(JUnit4.class).

这些答案都不适合我。这个答案并不能解决OP的问题,但由于这篇文章是唯一出现在谷歌上这个问题的帖子,所以我在这里分享我的答案。

我在为 Android 编写单元测试时遇到了这个问题。问题是我正在测试的活动延长了AppCompatActivity而不是Activity。为了解决这个问题,我能够用Activity替换AppCompatActivity,因为我并不真正需要它。这可能不是每个人的可行解决方案,但希望了解根本原因会对某人有所帮助。

使用 JUnit 5 或更高版本时。您必须注入带有注释的类@Mock@BeforeEach设置中。

就我而言,这是由于错误导入@Test注释

确保使用以下导入

import org.junit.jupiter.api.Test;

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

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

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.我没有检查它并更改了图书馆,对不起。

我试图嘲笑"最终"方法,这显然是问题所在。

处理此问题的正确方法是使用接口并模拟该接口,但是我无法控制"最终"方法所在的库。

Mockito 2可以处理模拟最终方法。将文本文件添加到项目的 src/test/resources/mockito-extensions 目录中,名为 org.mockito.plugins.MockMaker,并添加一行文本:

mock-maker-inline

之后,模拟最终方法应该可以正常工作。

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

这不会回答 OP 的原始查询,但它在这里尝试帮助其他人处理 Mockito 空指针异常 (NPE(。

我的 NPE 正在发生,因为我没有明确将测试依赖项下的类设置为我模拟的类。因此,被测试的类无法找到其所需的依赖项,从而创建了 NPE。我倾向于不模拟被测试的类(即使用new关键字(,以确保我获得我的原生类行为进行测试。

由于我无法控制的原因,我仍在使用 Junit 4。工作示例;

类测试下测

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
}

相关内容

  • 没有找到相关文章

最新更新