Mockito - NullpointerException when stubbing Metho

2019-01-31 01:21发布

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

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:

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.

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.

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.

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


}

11条回答
唯我独甜
2楼-- · 2019-01-31 01:46

None of these answers worked for me. This answer doesn't solve OP's issue but since this post is the only one that shows up on googling this issue, I'm sharing my answer here.

I came across this issue while writing unit tests for Android. The issue was that the activity that I was testing extended AppCompatActivity instead of Activity. To fix this, I was able to just replace AppCompatActivity with Activity since I didn't really need it. This might not be a viable solution for everyone, but hopefully knowing the root cause will help someone.

查看更多
Emotional °昔
3楼-- · 2019-01-31 01:50
@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 @Mock Annotation to Context 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); ,

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

查看更多
别忘想泡老子
4楼-- · 2019-01-31 01:51

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

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.

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

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

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

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

查看更多
【Aperson】
5楼-- · 2019-01-31 01:53

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

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

if you @RunWith(JUnit4.class).

查看更多
萌系小妹纸
6楼-- · 2019-01-31 01:55

Corner case:
If you're using Scala and you try to create an any matcher on a value class, you'll get an unhelpful NPE.

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

when(mock.someMethod(ValueClass(anyInt))).thenAnswer {
   ...
   val v  = ValueClass(invocation.getArguments()(0).asInstanceOf[Int])
   ...
}

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

查看更多
Emotional °昔
7楼-- · 2019-01-31 01:56

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.

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

Hope that helps someone.

Cheers

查看更多
登录 后发表回答