Mocking Static Methods in Android: Let’s Wrap it up

When writing local unit tests in Android, one of the limitiations that you face is that the tests are run against a version of android.jar that does not have any code. As the documentation explains, any dependency on Android code must be mocked.

A quick example of a simple unit test:

public class ClassUnderTest {

public String methodUnderTest(String str)
{
    if (PhoneNumberUtils.isGlobalPhoneNumber(str))
    {
      return "yes";
    }
    else
    {
      return "no";
    }
  }
}

@RunWith(JUnit4.class)
public class TestThatFails {

private ClassUnderTest classUnderTest;

  @Before
  public void setup() {
    classUnderTest = new ClassUnderTest();
  }

  @Test
  public void testTheClass() {
    String result = classUnderTest.methodUnderTest("1234");
    assertEquals("yes", result);
  }
}

When this test is run, it will fail with the following error:

java.lang.RuntimeException: Method isGlobalPhoneNumber in android.telephony.PhoneNumberUtils not mocked. See http://g.co/androidstudio/not-mocked for details

The class we are testing has a dependency on the Android utility library PhoneNumberUtils. In order for the test to run successfully, this Android dependency must be mocked.

All the example code for this post is available at this gist.

Mockito: No to Static Methods

Google’s suggested way to mock Android dependencies is to use Mockito. This would generally be fine, however in our example this will not work because Mockito does not support mocking static methods.

This discussion shows that the Mockito contributors consider static methods to be an anti-pattern for various reasons, e.g.

  • The dependency on the static method becomes hard wired in the code.
  • This makes mocking and testing difficult.

Hence they do not support it as they don’t want to encourage poor design.

So what are some other way to make our test work?

  • If this was plain old Java instead of Android, I could have used PowerMockito to mock the static methods. However I have found using PowerMock to be problematic in Android.
  • If you only use a few static methods, you could just copy the code into your app assuming the the source was available. Of course this means more code to maintain, and is not sustainable if you use a lot of static methods.
  • You could wrap the static method call and internally delegate to the static method. The wrapper could then be mocked. This is the option we will be discussing.

Wrapper Classes

One solution is to create a wrapper class for the Android classes that have the static method, and add that wrapper as a dependency.

public class PhoneNumberUtilsWrapper {

  public boolean isGlobalPhoneNumber(String phoneNumber)
  {
    return PhoneNumberUtils.isGlobalPhoneNumber(phoneNumber);
  }
}

public class ClassUnderTestWithWrapper {

  private PhoneNumberUtilsWrapper wrapper;

  public ClassUnderTestWithWrapper(PhoneNumberUtilsWrapper wrapper) {
    this.wrapper = wrapper;
  }

  public String methodUnderTest(String str)
  {
    if (wrapper.isGlobalPhoneNumber(str))
    {
      return "yes";
    }
    else
    {
      return "no";
    }
  }
}

Here I have created a wrapper class for PhoneNumberUtils which is now a dependency of the class under test.

@RunWith(JUnit4.class)
public class TestWithWrapper {

  @Mock
  PhoneNumberUtilsWrapper wrapper;

  private ClassUnderTestWithWrapper classUnderTest;

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

    classUnderTest = new ClassUnderTestWithWrapper(wrapper);
  }

  @Test
  public void testTheClass() {
    when(wrapper.isGlobalPhoneNumber(anyString())).thenReturn(true);

    String result = classUnderTest.methodUnderTest("1234");
    assertEquals("yes", result);
  }
}

Because the wrapper class can be mocked, and the method call in the class under test is not static, the test can now pass.

One problem with this solution is when the class under test depends on static methods from many Android libraries. For instance, what happens if the class under test also needs to use TextUtils, DateUtils, etc. Suddenly you end up with lots more boilerplate code, more constructor parameters, etc.

Wrapper Methods

Another way is to wrap the static method call in a non-static method in the class under test.

public class ClassUnderTestWithWrappedMethod {

  public String methodUnderTest(String str)
  {
    if (isGlobalPhoneNumber(str))
    {
      return "yes";
    }
    else
    {
      return "no";
    }
  }

  // can't be private access
  boolean isGlobalPhoneNumber(String phoneNumber)
  {
    return PhoneNumberUtils.isGlobalPhoneNumber(phoneNumber);
  }
}

In order for this to work, in the test we have to use Mockito spy. Also note that the wrapped methods have to be accessible in the test, and therefore can’t be private.

@RunWith(JUnit4.class)
public class TestWithWrappedMethod {

  private ClassUnderTestWithWrappedMethod classUnderTest;

  private ClassUnderTestWithWrappedMethod classUnderTestSpy;

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

    classUnderTest = new ClassUnderTestWithWrappedMethod();
    classUnderTestSpy = Mockito.spy(classUnderTest);
  }

  @Test
  public void testTheClass() {
    doReturn(true).when(classUnderTestSpy)
    .isGlobalPhoneNumber(anyString());

    String result = classUnderTestSpy.methodUnderTest("1234");
    assertEquals("yes", result);
  }
}

Here we are running the test on the spy class, which will delegate method calls to the real class under test. However we can create stubs for the methods that wrap the static method calls to Android libraries.

As I have mentioned, one disadvantage is that the wrapped methods cannot be private, which is not ideal from an OO design point of view. But then you have to make similar compromises if you are using libraries such as Dagger or Butterknife.

Conclusion

Both of these wrapping solutions can work, but it’s probably a good idea to be consistent and stick with doing it one way if you can. Which method works better may depend on your app architecture, e.g. are you using dependency injection.

Static Methods: Good or Bad? Does it matter?

In this post I am not getting into the argument about whether static methods are good or bad design (although my personal opinion is that their use should be limited). There are plenty of arguments about this issue on the internet already.

However, in the Java world they are a fact of life.

Many utility classes in Java, Android and many popular libraries are not real OO classes, but collections of procedural functions. The functions are often written as static methods and grouped by functionality.

Whether you like static methods or not, we all have to learn to deal with them in a pragmatic way.

Android Studio 3.0 – Initial Impressions of Tool Support

I have been using Android Studio 3.0 since since the alpha versions, and it is good to see it finally released.

This is just some initial comments on using some common and new Android tools and libraries with the 3.0 version of Android Studio and the associated Android Gradle plugin.

Hopefully this will be useful for anyone thinking of upgrading from Android Studio 2.x.

Java 8 Finally, Maybe

Java 8 was released back in 2014, and with Android Studio 3.0 it is finally supported in Android. Finally I can say goodbye to RetroLambda (although many thanks to the authors for this very useful library).

Just be aware that many of the Java 8 language features will only be available if the minSkdVersion is 24.

Since devices running Nougat or Oreo are still in the minority, supporting older versions will continue to be an issue for a while if you want to use Java 8. Some ideas floated around to support older API version, are to have min API version flavors or  do Build.VERSION checks for the API version in the code to provide alternative code paths.

Desugar

The Jack tool chain has been replaced with the desugar tranformation process to support Java 8. Some older libraries and code may have some problems with this build stage.

JUnit 5

JUnit 5 has also been released recently, and with the help of this plugin you can use it for unit testing in Android Studio.

However if you use JUnit 4 Rules in your tests, there is limited support in JUnit 5 as they are meant to be replaced with extensions. Some Rules may be supported with the JUnit 5 migration support, but if not you will have to wait until the Rules are rewritten as extensions or not use the Rules at all.

Of course this is only for unit testing. Instrumentation tests still depend on JUnit 4 and the AndroidJUnitRunner.

Update (7 Dec 2017)

The authors of the JUnit5 plugin have stated that they now have support for JUnit 5 in instrumentation tests. I won’t be using it for a while since it requires the minSkdVersion to be 26. If anyone has tried this, please let me know how well it works.

Architecture Components, RxJava

I have also been using some of Google’s Architecture Components, but only the ViewModel and LiveData. This is another alternative to design patterns such as MVP or MVVM with Databinding.

If you use RxJava, then this will of course continue to work as it is compatible with Java 6. You may consider replacing RxJava with the more light weight LiveData for activities and fragments, and they can be adapted to each other.

Dependency Injection with Dagger

I have had no problems with Google’s Dagger, but be aware of the API changes for the Android Gradle plugin 3.0 in the gradle build file (e.g. implemention instead of compile, annotationProcessor instead of apt, etc).

See the Android Gradle plugin 3.0 migration guide.

Butterknife, Timber

Some common utilities like Butterknife and Timber for logging are working fine. I’m also using the slf4j binding for Timber without any trouble.

JRebel for Android

During the Android Studio alpha and beta process, JRebel for Android was always playing catch up with the latest version. I still have issues with the current version (2.4.14) of their free edition, so I am using instant run instead at the moment.

I’m a big fan of JRebel so I’m hoping they will have a stable version of their android plugin for Android Studio 3.0 soon.

Update (31 Jan 2018)

JRebel for Android is no longer being actively developed.

AOP with AspectJ

There are various AspectJ plugins for Android,  and the one I have been using in Android Studio 2.x was this one. Unfortunately it doesn’t support the Android plugin for Gradle 3.0 yet, but the author seem to be working on it so hopefully the support will be there soon.

Update (15 Nov 2017)

Version 3.2.0 of the GradleAspectJ-Android plugin now supports the Android plugin for Gradle 3.0. I like this plugin because it supports both aj files and annotation style aspects.

Things will get better

Of course since Android Studio 3.0 has only recently got general release, we should expect tool and library support to improve going forward.

I have only scratched the surface with some common Android tools and libraries, and there are many more around. Please let me know of your experiences with others.

Android UI Test: Mocking the ViewModel with or without Dagger? Part 2

In the first part of this post, I explored the approach of setting up a UI test with a mock ViewModel without using Dagger 2 for dependency injection. I used the GithubBrowserSample app from the Architecture Components sample code to demonstrate disabling Dagger for UI testing, even though the app itself uses Dagger.

Now, using Dagger

There are various ways of using Dagger to provide fake or mock version of dependencies for testing. Generally they involve writing test versions of the component and module classes.

Then when the Espresso test is run, somehow the Dagger object graph that is built (incorporating the mock dependencies provided by the test module) is used instead of the one used just for the app. Some of the ways to do this includes:

  • Include a hook into the application class to replace the Dagger components with the test versions.

http://blog.sqisland.com/2015/04/dagger-2-espresso-2-mockito.html

  • Once again create a test version of the application class in the androidTest directory. Here the test application would be a subclass of the app application class where the code to build the Dagger graph is overriden with the test version.

http://blog.sqisland.com/2015/12/mock-application-in-espresso.html

Of course, this would mean writing a custom test runner to use instead of AndroidJUnitRunner in the gradle build file.

public class YourApp extends Application implements hasActivityInjector {

  @Inject
  DispatchingAndroidInjector<Activity> dispatchingAndroidInjector;
  .
  .
  .
  @Override
  public DispatchingAndroidInjector<Activity> activityInjector() {
    return dispatchingAndroidInjector;
  }
}

// The test app in the androidTest directory
public class TestApp extends YourApp {

  @Override
  public AndroidInjector<Activity> activityInjector() {
    return new AndroidInjector<Activity>() {
      @Override
      public void inject(Activity instance) {
        // inject the fake / mock dependencies into the activity
        // e.g.
        .
        .
        .
        ((YourActivity)instance).viewModelFactory = ...
      }
    };
  }
}

Other options I came across in my research include:

  • There is the DaggerMock library that uses a JUnit Rule to override Dagger objects. This is a nice idea, but currently DaggerMock only has limited support for Dagger Android. In particular it does not handle abstract modules and methods which some of the Dagger Android annotations depend on.
  • Include a hook in the activity to set dependencies.

https://blog.stylingandroid.com/architecture-components-summary/

Disadvantages, again

As I mentioned in the previous post, any of these approaches that uses a custom test application class for instrumentation testing would apply the same Dagger object graph to all the tests. This is not suitable for my situation where I only want to mock the ViewModel for the UI tests, but use the real one for other tests.

Other ways require making code changes to the app just to accommodate testing. This is a bit of a hack and not good design.

One Possible Solution

The solution I decided to use was based on this gist. The test module was used to create a AndroidInjector that would inject a custom ViewModel factory into the test activity. In turn the custom ViewModel factory would provide the mock ViewModel.

.
.
return new AndroidInjector<MyActivity>() {
  @Override
  public void inject(MyActivity instance) {
    // create the viewmodel mocks
    MyViewModel viewModel = Mockito.mock(MyViewModel.class);

    // create the livedata used to return results
    MutableLiveData<Data> returnedData = new MutableLiveData<>();
    when(viewModel.getData()).thenReturn(returnedData);

    // set test data
    Data expectedData = ...
    returnedData.setValue(expectedData);

    // set the custom viewmodel factory that just returns the mocks
    instance.viewModelFactory = ViewModelUtil.createFor(viewModel);
  }
};

This approach did have the downside of requiring a lot of boilerplate code. But it also allowed me to only mock the ViewModel for the UI tests, without affecting the other tests.

Disclaimer

Please note that the opinions expressed in this post are not meant to apply to all instrumentation testing with Dagger.

They are only for the specific use case of trying to mock the ViewModel for my UI tests, while not affecting other instrumentation tests.

 

Spring Profiles and Reusable Tests, Part 2

In the 1st part of the post, we were able to use Spring profiles to inject a specific implementation of a class to test into some test cases. Now we will try to create a reusable test case by using Spring Dependency Injection and Spring profiles to inject the appropriate expected results when testing a particular implementation.

Firstly we need to get the expected test results into a format that be be injected by Spring DI into a test case.

public interface FormatResults {

  public String getExpectedResult(String testMethodName);
}

public abstract class BaseFormatResults implements FormatResults {

  private Map<String, String>  results;

  public BaseFormatResults()
  {
    results = new HashMap<String, String>();

    setUpResults();
  }

  protected abstract void setUpResults();

  protected void addResult(String testMethodName, String result)
  {
    results.put(testMethodName, result);
  }

  @Override
  public String getExpectedResult(String testMethodName)
  {
    return results.get(testMethodName);
  }
}

public class HelloResults extends BaseFormatResults {

  @Override
  protected void setUpResults()
  {
    addResult("testDave", "Hello Dave");
  }
}

public class GoodByeResults extends BaseFormatResults {

  @Override
  protected void setUpResults()
  {
    addResult("testDave", "Good Bye Dave");
  }
}

For the sample code, a class is created as a wrapper around a map, which stores the expected test results for a test case. The expected result for each test method is keyed by the test method name in the map. Then some methods are included for adding and retrieving these expected results.

I have also made this wrapper class implement an interface and be abstract so that it can be subclassed to add the expected results for a particular test class.

Next we refactor the Spring JavaConfig classes to include these result classes, so that they can be injected into the test case along with the implementation of the class to test.

@Configuration
public class CommonTestConfig {

  @Autowired
  LogTestConfiguration logTestConfiguration;

  @Bean
  public Formatter formatter()
  {
    return logTestConfiguration.formatter();
  }

  @Bean
  public FormatResults results()
  {
    return logTestConfiguration.results();
  }

  @Bean
  public String testData()
  {
    return "Dave";
  }
}

public interface LogTestConfiguration {

  public Formatter formatter();

  public FormatResults results();
}

@Configuration
@Profile("hello")
public class HelloConfig implements LogTestConfiguration {

  @Bean
  public Formatter formatter()
  {
    return new HelloFormatter();
  }

  @Bean
  public FormatResults results()
  {
    return new HelloResults();
  }
}

@Configuration
@Profile("goodbye")
public class GoodByeConfig implements LogTestConfiguration {

  @Bean
  public Formatter formatter()
  {
    return new GoodByeFormatter();
  }

  @Bean
  public FormatResults results()
  {
    return new GoodByeResults();
  }
}

An extra method is added to the ‘LogTestConfiguration’ interface to retrieve a result class. Then the extra @Bean method to the configuration classes for getting the appropriate result class based on the active Spring profile.

Lastly we again refactor the test case to use the updated configuration files.

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes={CommonTestConfig.class, HelloConfig.class, GoodByeConfig.class})
public class SpringProfileTest {

  @Autowired
  private Formatter formatter;

  @Autowired
  private FormatResults results;

  @Autowired
  private String testData;

  @Test
  public void testDave()
  {
    String result = formatter.format(testData);
    System.out.println("Result = " + result);

    String expected = results.getExpectedResult("testDave");

    assertEquals(expected, result);
  }

  // getters and setters left out for brevity ...
}

Here are the changes from the test case examples in the previous post:

  • there is now only one test case required to test either test class implemenation ‘HelloFormatter’ or ‘GoodByeFormatter’ (previously a separate test case was required for each)
  •  the results for the test is also now injected into the test case via Spring DI
  • all of the Spring configuration files are included in the @ContextConfiguration annotation
  • the @ActiveProfiles annotation has been left out, now we need to specify the active Spring profile to use external to the test case, this can be done by setting the ‘spring.profiles.active’ property before running the test case, and there are various ways to do this.

For the sample code, if you are running the test case using the Eclipse IDE, then this could be set in the Run Configuration for the JUnit test class.

Eclipse JUnit run configuration

If you are using Gradle, then just set the property in the build script in the ‘test’ task.

test {
  systemProperties 'spring.profiles.active': 'hello'
}

The Sample Code

You can download the sample code for this example, SpringProfileTestingExample2.zip from GitHub.

Note that I have kept the sample code very simple for the sake of brevity, and also to more clearly illustrate the point. For instance, you may need to add the @DirtiesContext annotation to the test classes if you don’t want the injected beans to be cached between tests.

Conclusion

Using Spring bean definition profiles, we can make test cases reusable in the particular scenario where we are testing different implementations of a class.

If you only have a few tests to run, then the this setup with the Spring profiles would be overkill.

However for my project, where I had many test cases, it allowed me to reuse them without having to duplicate them for each implementation of a class under test. Of course, it would also allow me to use those same test cases to test any future implementations of the class too.

Spring Profiles and Reusable Tests, Part 1

When writing test cases for an update to an open source project I was working on, I came across the issue of how to make test classes reusable.

I already had dozens of test cases written for testing a particular class. Now I had written another implementation of that class, and I wanted to reuse the test cases I already had, to avoid duplication.

I decided to see if I could use Spring profiles to do this.

Spring Profiles

Spring bean definition profiles allows the wiring of different beans in different environments.

One use of Spring profiles in testing is where different test data or application configurations can be injected into test cases depending on the profile. There are various examples of this:

However my requirements were a bit different.

  • more specifically I had various implementations of a class that logged an object graph and produce some output in differing formats.
  • I had many test cases written that would test a particular implementation of the logging class and then compare the generated logging with some expected output.
  • I wanted to run the same set of tests with the same test data, but testing different implementations of the logging class

So rather than changing the test data, what I wanted to change was the class under test and the expected results using Spring DI. Using profiles would allow me to reuse the same tests and test data.

Of course if there are only a few tests to run, this could also be achieved using parameterized tests. Then for each test you could use JUnit 4 to pass parameters for the test data and expected test results.

Here are some simple code examples, showing one way to use Spring profiles in tests.

Step 1: A Simple Test with Spring

Note: Here I’m also using Spring’s JavaConfig instead of XML for the application contexts, but either would work.

Firstly let’s create some classes to test. Here are 2 classes that do some string formatting, both of which have a common interface:

public interface Formatter {

  public String format(String name);
}

public class HelloFormatter implements Formatter {

  @Override
  public String format(String name) {
    return "Hello " + name;
  }
}

public class GoodByeFormatter implements Formatter {

  @Override
  public String format(String name) {
    return "Good Bye " + name;
  }
}

Now let’s write a simple JUnit test case for to test ‘HelloFormatter’, using Spring to inject the test class and test data.

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes={SimpleTestConfig.class})
public class SimpleTest {

	@Autowired
	private Formatter formatter;

	@Autowired
	private String testData;

	@Test
	public void testDave() {
		String result = formatter.format(testData);
		System.out.println("Result = " + result);

		String expected = "Hello Dave";

		assertEquals(expected, result);
	}

	// getters and setters left out for brevity ...
}

And here’s the JavaConfig used to wire the beans for the test.

@Configuration
public class SimpleTestConfig {

	@Bean
	public Formatter formatter()
	{
		return new HelloFormatter();
	}

	@Bean
	public String testData()
	{
		return "Dave";
	}
}

Now if we want to test the ‘GoodbyeFormatter’ implementation class as well, we could just write another test case and another Spring JavaConfig class, but this would mean code duplication.

So instead let’s try using Spring profiles to inject the appropriate test class into the test cases.

Step 2 : Using Spring Profiles

Firstly let’s refactor the Spring JavaConfig classes.

@Configuration
public class CommonTestConfig {

	@Autowired
	LogTestConfiguration logTestConfiguration;

	@Bean
	public Formatter formatter()
	{
		return logTestConfiguration.formatter();
	}

	@Bean
	public String testData()
	{
		return "Dave";
	}
}

public interface LogTestConfiguration {

	public Formatter formatter();

}

@Configuration
@Profile("hello")
public class HelloConfig implements LogTestConfiguration {

	@Bean
	public Formatter formatter()
	{
		return new HelloFormatter();
	}
}

@Configuration
@Profile("goodbye")
public class GoodByeConfig implements LogTestConfiguration {

	@Bean
	public Formatter formatter()
	{
		return new GoodByeFormatter();
	}
}

Notice we have split the configuration between 3 classes now:

  • there is one class that configures the beans required for all the test cases
  • there is one configuration file specifically for testing the ‘HelloFormatter’ class, and it has the annotation ‘@Profile(“hello”)’.
  • there is one configuration file specifically for testing the ‘GoodByeFormatter’ class, and it has the annotation ‘@Profile(“goodbye”)’.
  • the 2 configuration files that have profile annotations share a common interface so that they can, in turn, be injected into the common configuration file

This setup is base on the blog, SPRING 3.1 M1: INTRODUCING @PROFILE, which contains a more detailed explanation.

So here are the refactored test cases that use the new configuration files, one test class to test each formatter implementation class.

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes={CommonTestConfig.class, HelloConfig.class})
@ActiveProfiles("hello")
public class SpringProfileHelloTest {

	@Autowired
	private Formatter formatter;

	@Autowired
	private String testData;

	@Test
	public void testDave() {
		String result = formatter.format(testData);
		System.out.println("Result = " + result);

		String expected = "Hello Dave";

		assertEquals(expected, result);
	}

	// getters and setters left out for brevity ...
}

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes={CommonTestConfig.class, GoodByeConfig.class})
@ActiveProfiles("goodbye")
public class SpringProfileGoodbyeTest {

	@Autowired
	private Formatter formatter;

	@Autowired
	private String testData;

	@Test
	public void testDave() {
		String result = formatter.format(testData);
		System.out.println("Result = " + result);

		String expected = "Good Bye Dave";

		assertEquals(expected, result);
	}

	// getters and setters left out for brevity ...
}

Note that each test case class has the @ActiveProfiles annotation, so that only the appropriate test class is injected for testing. Also we have added the required configuration files to the @ContextConfiguration annotation.

The Sample Code

You can download the sample code for this example, SpringProfileTestingExample1.zip from GitHub.

The requirements to run the sample code are:

Next

We have achieved half of what we set out to do, by using Spring profiles to determine which implementation of a test class is used for each test case.

In the next part of this post, we will make further improvements so that we have one reusable test case able to test both test class implementations by injecting the expected test results as well.