Steppschuh Steppschuh - 1 month ago 10
Android Question

How to create a Bundle in a Unit test

I want to test a method that deals with Bundles. I'm unable to create a (non-null) Bundle object in the test environment, though.

Given the following code:

Bundle bundle = new Bundle();
bundle.putString("key", "value");
boolean containsKey = bundle.containsKey("key");


containsKey
is
true
if the code is executed in the application context, but
false
if executed in a unit test.

Service Context

Test Context

I can't figure out why that's the case and how to create a Bundle for my tests.

Answer

If your build script contains something like this:

testOptions {
    unitTests.returnDefaultValues = true
}

then it's a cause why your test doesn't fail even if your don't specify a mock for Bundle class.

There are a few options to deal with this problem:

  1. Use Mockito mocking framework to mock a Bundle class. Unfortunately, you have to write a lot of boilerplate code by yourself. For example you can use this method to mock a bundle object, so it will return you the right values by getString method:

     @NonNull
     private Bundle mockBundle() {
           final Map<String, String> fakeBundle = new HashMap<>();
           Bundle bundle = mock(Bundle.class);
           doAnswer(new Answer() {
           @Override
           public Object answer(InvocationOnMock invocation) throws Throwable {
                 Object[] arguments = invocation.getArguments();
                 String key = ((String) arguments[0]);
                 String value = ((String) arguments[1]);
                 fakeBundle.put(key, value);
                 return null;
           }
           }).when(bundle).putString(anyString(), anyString());
           when(bundle.get(anyString())).thenAnswer(new Answer<String>() {
                  @Override
                  public String answer(InvocationOnMock invocation) throws Throwable {
                       Object[] arguments = invocation.getArguments();
                       String key = ((String) arguments[0]);
                       return fakeBundle.get(key);
                   }
           });
           return bundle;
      }
    
  2. Use Robolectric framework that provides some kind of shadow classes for your unit tests. This allows you to use Android specific classes in unit testing and they will act properly. By using that framework your unit test will act properly almost without any changes from your side.

  3. The most undesirable by you, I guess, but well, it's eligible. You can make your test functional and run it on your android device or emulator. I do not recommend that way because of speed. Before executing tests you have to build a test apk, install it and run. This is super slow if you're going to do TDD.