5

I'm trying to unit test a broadcast receiver which listens for "com.android.music.metachanged" intents using JUnit4 and Mockito.

The broadcast receiver starts a service when it receives an intent. I want to assert that the service is started. I also want to assert that the string extra "artist" of the received intent is the same as the one of the sent intent.

This is what I have so far...

@RunWith(PowerMockRunner.class)
public class MusicBroadcastReceiverUnitTest {
    private MusicBroadcastReceiver mReceiver;

    @Mock
    private Context mContext;

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

        mReceiver = new MusicBroadcastReceiver();
    }

    @Test
    public void testStartMusicRegistrationService() {
        Intent intent = new Intent("com.android.music.metachanged");
        intent.putExtra("artist", "SampleArtist");

        mReceiver.onReceive(mContext, intent);
        assertNull(mReceiver.getResultData());

        ArgumentCaptor<Intent> argument = ArgumentCaptor.forClass(Intent.class);
        verify(mContext, times(1)).startService(argument.capture());

        Intent receivedIntent = argument.getValue();
        assertEquals("SampleArtist", receivedIntent.getStringExtra("artist"));
    }
}

But this fires a java.lang.RuntimeException: Method putExtra in android.content.Intent not mocked.

I checked this out, but I think the OP had a different problem, since they don't send out an intent from inside the test body.

Community
  • 1
  • 1
ExplodingTiger
  • 327
  • 2
  • 6
  • 18
  • 1
    Though it's not about ContentValues, this is a dupe of this problem: http://stackoverflow.com/q/36555136/1426891 – Jeff Bowman Dec 15 '16 at 21:08

2 Answers2

8

If you're like me and saw this error when running unit tests, but you didn't care about testing the putExtra portion of the code, you can use:

android {
    // ...
    testOptions {
        unitTests.returnDefaultValues = true
    }
}

in your app's build.gradle file.

Adam Johns
  • 35,397
  • 25
  • 123
  • 176
  • this is very interesting, it would be very kind if you add some explanation, that how it achieve that. It worked BTW. – Wajid Dec 09 '21 at 20:44
3

All right, I took a look at Method of ContentValues is not mocked as suggested by @Jeff Bowman. Sadly, that question doesn't provide any code, so I hope this will be useful for somebody...

@RunWith(PowerMockRunner.class)
public class MusicBroadcastReceiverUnitTest {
    private MusicBroadcastReceiver mReceiver;

    @Mock
    private Context mContext;

    @Mock
    private Intent androidIntent;

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

        mReceiver = new MusicBroadcastReceiver();
    }

    @Test
    public void testStartMusicRegistrationService() {
        try {
        PowerMockito.whenNew(Intent.class)
               .withArguments(String.class).thenReturn(androidIntent);
        } catch (Exception e) {
            e.printStackTrace();
        }
        when(androidIntent.getAction())
          .thenReturn("com.android.music.metachanged");
        when(androidIntent.getStringExtra("artist"))
          .thenReturn("SampleArtist");

        mReceiver.onReceive(mContext, intent);

        ArgumentCaptor<Intent> argument = ArgumentCaptor.forClass(Intent.class);
        verify(mContext, times(1)).startService(argument.capture());

        Intent receivedIntent = argument.getValue();
        assertEquals("SampleArtist", receivedIntent.getStringExtra("artist"));
    }
}

So yeah, I rather mocked "getStringExtra" than "putExtra". But it worked for me.

Community
  • 1
  • 1
ExplodingTiger
  • 327
  • 2
  • 6
  • 18