Java Mockito - 存根方法时出现 NullpointerException

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/33124153/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 14:21:22  来源:igfitidea点击:

Mockito - NullpointerException when stubbing Method

javatestingjunitmockitostubbing

提问by user5417542

So I started writing tests for our Java-Spring-project.

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

What I use is JUnit and Mockito. It's said, that when I use the when()...thenReturn() option I can mock services, without simulating them or so. So what I want to do is, to set:

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

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

But no matter which when-clause I do, I always get a NullpointerException, which of course makes sense, because input is null.

但是无论我使用哪个 when 子句,我总是得到 NullpointerException,这当然是有道理的,因为输入为空。

Also when I try to mock another method from an object:

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

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

There I also get a Nullpointer, because the method needs a variable, which isn't set.

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

But I want to use when()..thenReturn() to get around creating this variable and so on. I just want to make sure, that if any class calls this method, then no matter what, just return true or the list above.

但我想使用 when()..thenReturn() 来绕过创建这个变量等等。我只是想确保,如果任何类调用此方法,那么无论如何,只需返回 true 或上面的列表。

Is it a basically misunderstanding from my side, or is there something else wrong?

这基本上是我的误解,还是有其他问题?

Code:

代码:

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

And here is my test class:

这是我的测试课:

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


}

采纳答案by ahu

The default return value of methods you haven't stubbed yet is falsefor boolean methods, an empty collection or map for methods returning collections or maps and nullotherwise.

你还没有存根的方法的默认返回值是false布尔方法,一个空集合或映射返回集合或映射的方法等null

This also applies to method calls within when(...). In you're example when(myService.getListWithData(inputData).get())will cause a NullPointerException because myService.getListWithData(inputData)is null- it has not been stubbed before.

这也适用于when(...). 在你的例子中when(myService.getListWithData(inputData).get())会导致 NullPointerException 因为myService.getListWithData(inputData)null- 它之前没有被存根。

One option is create mocks for all intermediate return values and stub them before use. For example:

一种选择是为所有中间返回值创建模拟并在使用前存根它们。例如:

ListWithData listWithData = mock(ListWithData.class);
when(listWithData.get()).thenReturn(item1);
when(myService.getListWithData()).thenReturn(listWithData);

Or alternatively, you can specify a different default answer when creating a mock, to make methods return a new mock instead of null: RETURNS_DEEP_STUBS

或者,您可以在创建模拟时指定不同的默认答案,以使方法返回新模拟而不是 null: RETURNS_DEEP_STUBS

SomeService myService = mock(SomeService.class, Mockito.RETURNS_DEEP_STUBS);
when(myService.getListWithData().get()).thenReturn(item1);

You should read the Javadoc of Mockito.RETURNS_DEEP_STUBSwhich explains this in more detail and also has some warnings about its usage.

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

I hope this helps. Just note that your example code seems to have more issues, such as missing assert or verify statements and calling setters on mocks (which does not have any effect).

我希望这有帮助。请注意,您的示例代码似乎有更多问题,例如缺少 assert 或 verify 语句以及在模拟上调用 setter(这没有任何效果)。

回答by Ed Webb

I had the same problem and my issue was simply that I had not annotated the class properly using @RunWith. In your example, make sure that you have:

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

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

Once I did that, the NullPointerExceptions disappeared.

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

回答by Ryan Shillington

I had this issue and my problem was that I was calling my method with any()instead of anyInt(). So I had:

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

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

and I had to change it to:

我不得不将其更改为:

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

I have no idea why that produced a NullPointerException. Maybe this will help the next poor soul.

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

回答by anand krish

@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 {

 }
}

All the above commented codes are not required { mockContext = Mockito.mock(Context.class);}, if you use @MockAnnotation to Context mockContext;

以上所有注释代码都不需要{ mockContext = Mockito.mock(Context.class);},如果使用@MockAnnotationContext mockContext;

@Mock 
Context mockContext; 

But it will work if you use @RunWith(MockitoJUnitRunner.class)only. As per Mockito you can create mock object by either using @Mock or Mockito.mock(Context.class);,

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

I got NullpointerException because of using @RunWith(PowerMockRunner.class), instead of that I changed to @RunWith(MockitoJUnitRunner.class) it works fine

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

回答by Vituel

Corner case:
If you're using Scalaand you try to create an anymatcher on a value class, you'll get an unhelpful NPE.

特殊情况:
如果您使用Scala并尝试any值类上创建匹配器,您将得到一个无用的 NPE。

So given case class ValueClass(value: Int) extends AnyVal, what you want to do is ValueClass(anyInt)instead of any[ValueClass]

因此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])
   ...
}

This other SO questionis more specifically about that, but you'd miss it when you don't know the issue is with value classes.

另一个SO 问题更具体地说明了这一点,但是当您不知道问题与值类有关时,您就会错过它。

回答by smac89

For me the reason I was getting NPE is that I was using Mockito.any()when mocking primitives. I found that by switching to using the correct variant from mockito gets rid of the errors.

对我来说,我获得 NPE 的原因是我Mockito.any()在模拟原语时使用。我发现通过切换到使用来自 mockito 的正确变体可以消除错误。

For example, to mock a function that takes a primitive longas parameter, instead of using any(), you should be more specific and replace that with any(Long.class)or Mockito.anyLong().

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

Hope that helps someone.

希望能帮助某人。

回答by Ajay Vijayasarathy

faced the same issue, the solution that worked for me:

面临同样的问题,对我有用的解决方案:

Instead of mocking the service interface, I used @InjectMocks to mock the service implementation:

我没有模拟服务接口,而是使用 @InjectMocks 来模拟服务实现:

@InjectMocks
private exampleServiceImpl exampleServiceMock;

instead of :

代替 :

@Mock
private exampleService exampleServiceMock;

回答by Tal Joffe

For future readers, another cause for NPE when using mocks is forgetting to initialize the mocks like so:

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

Also make sure you are using JUnit for all annotations. I once accidently created a test with @Test from testNG so the @Before didn't work with it (in testNG the annotation is @BeforeTest)

还要确保所有注释都使用 JUnit。我曾经不小心使用 testNG 中的 @Test 创建了一个测试,因此 @Before 无法使用它(在 testNG 中,注释是 @BeforeTest)

回答by lcn

Ed Webb's answerhelped in my case. And instead, you can also try add

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

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

if you @RunWith(JUnit4.class).

如果你@RunWith(JUnit4.class)

回答by Serhii Bohutskyi

In my case, I missed add first

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

PowerMockito.spy(ClassWhichNeedToBeStaticMocked.class);

so this can be helpful to somebody who see such error

所以这对看到此类错误的人会有所帮助

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)