2

This is a duplicate of this question. There are bunch of similar questions/answers as well but none helped me. As there are hundreds of developers accepted some answers I am probably wrong somewhere and have no idea where is my problem!

This is my sample class and I want to test its method.

final class NavigationBuilder {

    @VisibleForTesting List<Intent> mIntentList = new ArrayList<>(5);

    @VisibleForTesting
    void addNextScreenBasedOnBookingStatus(final Booking booking) {
        final ChatMsgDbAsyncHelper helper = new ChatMsgDbAsyncHelper();

        if (booking == null) {
            helper.cleanAllMessages(mContext); // <= Crash here
        } 

    }
}

This is my test class:

@RunWith(PowerMockRunner.class)
@PrepareForTest({ChatMsgDbAsyncHelper.class, SplashActivity.class})
public class NavigationBuilderTest {

    private SplashActivity mActivity;
    private NavigationBuilder mNavBuilder;

    @Before
    public void setUp() throws Exception {

        mActivity = new SplashActivity();
        ISplashView view = mock(ISplashView.class);
        PassengerStorage passengerStorage = mock(PassengerStorage.class);

        mNavBuilder = new NavigationBuilder(mActivity, view, passengerStorage);
    }

    @Test
    public void addNextScreenBasedOnBookingStatus_whenBookingIsNull() throws Exception {
        ChatMsgDbAsyncHelper spy = PowerMockito.spy(new ChatMsgDbAsyncHelper());
        PowerMockito.doNothing().when(spy).cleanAllMessages(mActivity);

        mNavBuilder.addNextScreenBasedOnBookingStatus(null);

        assertTrue(mNavBuilder.mIntentList.isEmpty());
    }
}

Test fails and the reason is NullPointerException because test is running logic inside of helper.cleanAllMessages(mContext);. My expectation from above mock is those logic should not be performed.

Caused by: java.lang.NullPointerException at com.xxx.xxx.db.entities.ChatMessageTable.(ChatMessageTable.java:23)

halfer
  • 19,824
  • 17
  • 99
  • 186
Hesam
  • 52,260
  • 74
  • 224
  • 365

2 Answers2

0

Your logic in the given code is to do nothing when you're passing mActivity object: PowerMockito.doNothing().when(spy).cleanAllMessages(mActivity);

But what you're actually passing is null: mNavBuilder.addNextScreenBasedOnBookingStatus(null);

Also, you have to pass this "spy" object in the test class to make your mock logic work. May be you can try something like this -

PowerMockito.whenNew(ChatMsgDbAsyncHelper.class).withNoArguments().thenReturn(spy);
PowerMockito.doNothing().when(spy).cleanAllMessages(mActivity); // or null, as per your requirement

and then pass your mActivity object to the method:

mNavBuilder.addNextScreenBasedOnBookingStatus(mActivity); // or pass null, as per your requirement
blu3
  • 123
  • 1
  • 12
  • Thanks for your comment. Yup, I actually saw similar answer in that link and didn't get what I expected after testing based on this approach. I don't know why but did not work and I got similar output I mentioned in my question. – Hesam Feb 17 '17 at 18:52
0

The problem was my understanding :)

I changed signature of the method under test with following and could test it. So in this case I am passing instance of ChatMsgDbAsyncHelper to the method rather than create it within method.

@VisibleForTesting
    void addNextScreenBasedOnBookingStatus(final Booking booking, final ChatMsgDbAsyncHelper chatMsgHelper) {
...
}

and test works fine now:

@Test
public void addNextScreenBasedOnBookingStatus_whenBookingIsNull() throws Exception {
    ChatMsgDbAsyncHelper mChatMsgHelper = PowerMockito.spy(new ChatMsgDbAsyncHelper());
    doNothing().when(mChatMsgHelper).cleanAllMessages(any(Context.class));

    mNavBuilder.addNextScreenBasedOnBookingStatus(null, mChatMsgHelper);

    assertTrue(mNavBuilder.mIntentList.isEmpty());
}
Hesam
  • 52,260
  • 74
  • 224
  • 365