RxPreferences and Dagger

I have been rewriting a Settings (Preferences) activity for an old Android app. Since I was using RxJava in the app, I decided to try out RxPreferences which allows you to use SharedPreferences with a reactive wrapper.

I found it quite good to use, although the blog post that accompanies it is a bit out of date. While I did’t use RxBinding with it, it still had these advantages:

Inject RxPreferences with Dagger

Getting the preferences to where they are needed can be done with Dependency Injection with libraries such as Dagger 2. For instance, this is an example of a Dagger module that provides application scope dependencies with RxSharedPreferences setup:

@Module
class AppModule {

  // the application context required to get the shared preferences
  @Singleton
  @Provides
  Context provideContext(Application application) {
    return application.getApplicationContext();
  }

  @Provides
  @Singleton
  SharedPreferences provideSharedPreferences(Context context) {
    return PreferenceManager.getDefaultSharedPreferences(context);
  }

  @Provides
  @Singleton
  RxSharedPreferences provideRxSharedPreferences(SharedPreferences sharedPreferences) {
    return RxSharedPreferences.create(sharedPreferences);
  }
}

Then inject RxSharedPreferences into the classes that will use it.

public class MyActivity extends AppCompatActivity {

  // RxSharedPreferences injected into a field for an activity
  @Inject
  RxSharedPreferences rxSharedPreferences;

  @Override
  public void onCreate(Bundle savedInstanceState)
  {
    // I'm using the Dagger Android library to inject dependencies
    AndroidInjection.inject(this);

    super.onCreate(savedInstanceState);
    setContentView(R.layout.main_activity);
  }

  private void someMethod()
  {
    <Preference<String> myPreference =   rxSharedPreferences.getString("pref_key");
    String stringFromPreference = myPreference.get();

    // do something with the string obtained from the preference
  }
}

Inject Preferences directly

Alternatively you can inject the Preference(s) rather than RxSharedPreferences, by setting up the Preference in the Dagger module.

class AppModule {

  @Singleton
  @Provides
  Context provideContext(Application application) {
    return application.getApplicationContext();
  }

  @Provides
  @Singleton
  SharedPreferences provideSharedPreferences(Context context) {
    return PreferenceManager.getDefaultSharedPreferences(context);
  }

  @Provides
  @Singleton
  RxSharedPreferences provideRxSharedPreferences(SharedPreferences sharedPreferences) {
    return RxSharedPreferences.create(sharedPreferences);
  }

  // Preference configured with hard-coded preference key
  @Provides
  @Named("myPreference")
  @Singleton
  Preference<String> provideMyPreference(RxSharedPreferences rxPreferences) {
    return rxPreferences.getString("my_preference_key");
  }

  // Preference configured with preference key retrieved from string resource
  @Provides
  @Named("myPreferenceUsingResource")
  @Singleton
  Preference<String> provideMyPreferenceUsingResource(Context context, RxSharedPreferences rxPreferences) {
    return rxPreferences.getString(context.getString(R.string.pref_my_preference_key));
  }
}

Notice that, as an example, I have configured 2 Preference’s in the module, one with the preference key hard-coded and the other with the preference key retrieved from string resources.

Also I have added the @Named anotation, which in this case is to distinguish the two Preferences since they are both of the type String. Even if I didn’t have multiple Preferences of the same type, I think it is a good idea to qualify them for better documentation (see the Dagger documentation to learn about qualifiers.

Then inject the Preference(s) instead of RxSharedPreferences.

public class MyActivity extends AppCompatActivity {

  @Inject
  @Named("myPreference")
  Preference<String> myPreference;

  @Override
  public void onCreate(Bundle savedInstanceState)
  {
    AndroidInjection.inject(this);

    super.onCreate(savedInstanceState);
    setContentView(R.layout.main_activity);
  }

  private void someMethod()
  {
    String stringFromPreference = myPreference.get();

    // do something with the string obtained from the preference
  }
}

Then we can also use the injected Preference to observe changes to the it.

public class MyActivity extends AppCompatActivity {

  @Inject
  @Named("myPreference")
  Preference<String> myPreference;

  private Disposable disposable;
 
  @Override
  public void onCreate(Bundle savedInstanceState)
  {
    AndroidInjection.inject(this);

    super.onCreate(savedInstanceState);
    setContentView(R.layout.main_activity);
 
    disposable = myPreference.asObservable()
      .subscribe(pref -> doSomething(pref));
  }
}

Custom Preference Types

In the blog for the RxPreferences library, it demonstrates getting a Preference for a custom type by creating an Adapter class for it. In the current version, this has been replaced with a class that implements the Preference.Converter interface instead.

Here is a simple example that converts a preference stored as a String into a Preference<Boolean>. Firstly create the Converter class:

public final class BooleanStringConverter implements Preference.Converter<Boolean> {

  @NonNull
  @Override
  public Boolean deserialize(@NonNull String serialized) {
    return Boolean.parseBoolean(serialized);
  }

  @NonNull
  @Override
  public String serialize(@NonNull Boolean value) {
    return String.valueOf(value);
  }
}

Then to get the Preference, use getObject() with the Converter class as a parameter. In this example I have added it to the Dagger module.

@Provides
@Singleton
BooleanStringConverter provideBooleanStringConverter() {
  return new BooleanStringConverter();
}

@Provides
@Named("myBooleanPreference")
@Singleton
Preference<Boolean> provideMyBooleanPreference(RxSharedPreferences rxPreferences, BooleanStringConverter booleanStringConverter) {
  return rxPreferences.getObject("my_preference_key", FALSE, booleanStringConverter);
}

Using the Preference with the Converter, as well as Dagger, meant I didn’t have type conversion code scattered throughout the app.

Gradle Dependencies for Java, use compile or implementation?

While I was explaining to a colleague about using Gradle for Java projects (he was moving away from Maven), we came across various code samples. Some of the examples were using the compile configuration for dependencies, while others were using implements and api.


dependencies {
compile 'commons-httpclient:commons-httpclient:3.1'
compile 'org.apache.commons:commons-lang3:3.5'
}


dependencies {
api 'commons-httpclient:commons-httpclient:3.1'
implementation 'org.apache.commons:commons-lang3:3.5'
}

This post was a summary based on the documentation and StackOverflow questions to explain to him which configurations to use.

New Dependency Configurations

Gradle 3.4 introduced the Java-library plugin, which included the then new configurations implementation and api (amongst others). These were meant to replace the compile configuration which was deprecated for this plugin. The idea was that the new configurations would help to prevent leaking of transitive dependencies for multi-module projects.

Please note that in this post I am just using the compile vs implementation/api configurations as an example. Other new replacement configurations were introduced as well, please read the documentation for further information.

Java

For a Java project using Gradle 3.4+, then it depends on whether you are build an application or a library.

For a library project or a library module in a multiple module project, it is recommended to use the Java-library plugin, so in build.gradle use this

apply plugin: 'java-library'

instead of

apply plugin: 'java'

Then you would use either implementation or api, depending on whether you want to expose the dependency to consumers of the library.

For a plain application project, you can stick with the java plugin and continue to use the compile configuration. Having said that, I have tried using the Java-library plugin for an app project and it seems to work fine.

Android

For an Android project, the new configurations came with the Android Gradle Plugin 3.0. So unless you are still using the 2.x version of Android Studio / Android Gradle plugin, the use of compile is deprecated. So you should use implementation, even for an app.

In fact, when I recently upgraded my Android Studio, it came up with the message:

Configuration ‘compile’ is obsolete and has been replaced with ‘implementation’.
It will be removed at the end of 2018

I think this also applies if you use Kotlin instead of Java.

Groovy

How about a project with Groovy as well as Java? This can be for a mixed Groovy / Java project, or for a Java project which needs Groovy for some support tools (such as Spock or Logback configuration).

In the past I have used the Groovy plugin instead of the Java plugin for mixed projects. The Groovy plugin extends the Java plugin and will handle the compilation for Java sources as well as Groovy sources.

apply plugin: 'groovy'

You can continue to do this for Java application modules, but the documentation states that the Groovy plugin has compatibility issues with the Java-library plugin so will need a work around for library modules.

Of course this short post is for newbies, and has only scratched the surface in terms of learning about all the new dependency configurations.

 

JRebel for a Gradle Spring Boot App

There is some documentation on how to add JRebel to a Spring Boot app that uses Gradle as the build tool. It is basic but works fine.

All you have to do is to add a few lines to build.gradle:

if (project.hasProperty('rebelAgent')) {
 bootRun.jvmArgs += rebelAgent
}

Then set the property in gradle.properties:

rebelAgent=-agentpath:[path/to/JRebel library]

However there are several ways to improve on this.

Make JRebel Optional

For instance, what if you don’t always want JRebel everytime you start the app with ‘bootRun’? JRebel plugins for IDE’s like Intellij IDEA are smart enough to give you the option of running your app with or without JRebel

There would be several ways of doing this, but one would be to add the JRebel startup configuration in an optional task.


task addRebelAgent << {
  if (project.hasProperty('rebelAgent')) {
    bootRun.jvmArgs += rebelAgent
  }
  else
    println 'rebelAgent property not found'
}

task rebelRun(dependsOn: ['addRebelAgent', 'bootRun'])

Now running ‘bootRun’ would start the app normally, and if you want JRebel then use the ‘rebelRun’ task instead. I have also added a debug message if the ‘rebelAgent’ property is not available.

Another way would be to pass an optional property to the ‘bootRun’ task to use as a flag whether to add JRebel or not.

if (project.hasProperty('rebelAgent') &&
    project.hasProperty('addJRebel')) {
 bootRun.jvmArgs += rebelAgent
}

Then to use JRebel you just need to add the extra property.

gradle bootRun -PaddJRebel=true

Finding the Rebel Base

Putting the path to the JRebel library to use as the agent in a properties file allows multiple developers to have their own version. However the path is still hard-coded, which is something that should be avoided if possible.

Another way to specify the path is to use a system environment variable to point to where JRebel is installed. JetBrains recommends using REBEL_BASE. Once set up, that allows you to use the environment variable in multiple ways, e.g. Gradle build files, command line, build scripts, etc.

Here is an example using the additional ‘addRebelAgent’ task that I specified earlier, that I use on my Windows 64 machine.


task addRebelAgent << {
  project.ext {
    rebelAgent = "-agentpath:${System.env.REBEL_BASE}${rebelLibPath}"
  }
  if (project.hasProperty('rebelAgent')) {
    bootRun.jvmArgs += rebelAgent
  }
  else
    println 'rebelAgent property not found'
}

task rebelRun(dependsOn: ['addRebelAgent', 'bootRun'])

And in gradle.properties I have specified the path to the agent library from the JRebel installation location.


rebelLibPath=\\lib\\jrebel64.dll

All I’ve done here is to build the path in the ‘rebelAgent’ property from the REBEL_BASE environment variable and another property specifying the internal path to the library.


rebelAgent = "-agentpath:${System.env.REBEL_BASE}${rebelLibPath}"

 

 

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&amp;lt;Activity&amp;gt; dispatchingAndroidInjector;
  .
  .
  .
  @Override
  public DispatchingAndroidInjector&amp;lt;Activity&amp;gt; activityInjector() {
    return dispatchingAndroidInjector;
  }
}

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

  @Override
  public AndroidInjector&amp;lt;Activity&amp;gt; activityInjector() {
    return new AndroidInjector&amp;lt;Activity&amp;gt;() {
      @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.

 

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

An Android app I’m currently working on has the following architecture:

When it came to testing the views , I wanted to write some UI tests using Espresso. These would just test just the activities and fragments with a mock backend.

With the Architecture Components I thought this would be fairly simple since all the interactions between the view and the backend services should be done through the ViewModel. Hence all I would need to do is to provide a mock ViewModel (in my case using Mockito).

Additionally I wanted to find a solution that:

  • was simple and straightforward, without the need for workarounds or hacks if possible
  • did not require any changes or additional code in the app just to accommodate testing

Looking at the Google sample code – no Dagger for UI Tests!

Since Google provides sample code for the Architecture Components, that’s the first place I looked. In particular the GithubBrowserSample seemed to be what I was after, this is from the README:

UI Tests

The projects uses Espresso for UI testing. Since each fragment is limited to a ViewModel, each test mocks related ViewModel to run the tests.

However, when I looked at the sample code for their UI tests, I was in for a surprise. Although the sample app itself uses Dagger DI, the UI tests do not.

This differs from most examples of testing Dagger applications, where it is advocated to write additional Components and Modules to inject fake dependencies for testing.

How it is done? The Setup.

Since I couldn’t find any documentation for these UI tests , here is a quick summary of how the GithubBrowserSample apps mocks the ViewModel without using Dagger. This basically involves using test version of the application and activity classes which do not invoke the Dagger injection code.

ViewModel Factory

Although it is possible to inject a ViewModel into an activity or fragment with Dagger, I will be using a custom ViewModel factory and injecting that instead. This is done for the following reasons:

  • Injecting a ViewModel class is only possible for ViewModels that have a default (empty) constructor. If the ViewModel constructor has parameters, then you need to inject a factory class that implements ViewModelProvider.Factory.
  • It seems to be a common pattern when using Dagger with the ViewModel to create a Module to encapsulate the ViewModel injection code. This Module would bind the ViewModel classes used in the app into a map. It would also provide the ViewModel factory class, which in turn uses the map to create the ViewModel classes. This is the pattern used in the GithubBrowserSample.

Here is a brief description of the UI tests for the fragments in the sample code:

  • Create a test application class.

This is just a dummy application class that does not invoke the Dagger code that builds the object graph.

https://github.com/googlesamples/android-architecture-components/blob/master/GithubBrowserSample/app/src/androidTest/java/com/android/example/github/TestApp.java

  • Create a test activity class.

This is just a dummy activity class to contain the fragment to be tested. It allows the fragment to be inserted into it.

https://github.com/googlesamples/android-architecture-components/blob/master/GithubBrowserSample/app/src/debug/java/com/android/example/github/testing/SingleFragmentActivity.java

This test runner will used the test application class instead of the application class for the app.

https://github.com/googlesamples/android-architecture-components/blob/master/GithubBrowserSample/app/src/androidTest/java/com/android/example/github/util/GithubTestRunner.java

@Override
 public Application newApplication(ClassLoader cl, String className, Context context)
 throws InstantiationException, IllegalAccessException, ClassNotFoundException {
   return super.newApplication(cl, TestApp.class.getName(), context);
}
android {
  .
  .
  .
  testInstrumentationRunner "com.android.example.github.util.GithubTestRunner"
}

How it is done? The UI Test.

The GithubBrowserSample has several UI tests for different fragments, but they follow the same basic pattern. Let’s use this one as an example:

https://github.com/googlesamples/android-architecture-components/blob/master/GithubBrowserSample/app/src/androidTest/java/com/android/example/github/ui/user/UserFragmentTest.java

Remember that when the UI tests are run, there is no Dagger dependency injection.

  • Use the test activity class to hold the fragment to be tested, instead of the activity used in the app. This is done in the ActivityTestRule used in setting up Espresso tests.
@Rule
public ActivityTestRule&lt;SingleFragmentActivity&gt; activityRule =
new ActivityTestRule&lt;&gt;(SingleFragmentActivity.class, true, true);
  • Before the test is run, setup the mock ViewModel.
@Before
public void init() {
.
.
  viewModel = mock(UserViewModel.class);
  when(viewModel.getUser()).thenReturn(userData);
  when(viewModel.getRepositories()).thenReturn(repoListData);
.
.
}
  • Set the ViewModel factory field in the fragment (which would have been injected in the app) to a fake factory class that just passes the mocked ViewModel. Of course the field needs to be accessible from the test class for this to happen (i.e. public or default package access).
@Before
 public void init() {
.
.
  fragment.viewModelFactory = ViewModelUtil.createFor(viewModel);
.
.
 }
  • Put the fragment into the test activity.
@Before
 public void init() {
.
.
.
  activityRule.getActivity().setFragment(fragment);
 }
  • Because this fragment uses LiveData to get data from the ViewModel, the test data is inserted into the LiveData returned from the mock ViewModel.
@Test
public void loadingWithUser() {
  User user = TestUtil.createUser("foo");
  userData.postValue(Resource.loading(user));
.
.
}

A simple approach

That’s it.

With this approach there is no need to worry about the Dagger configuration. Just mock the ViewModel to return the data you want for the Espresso test.

Disadvantages

  1. Using a custom test runner and test application means that all of instrumentation tests in the androidTest directory will have Dagger disabled.

But what if you have other instrumentation tests where you do want to use the Dagger injected classes, in additition to the UI tests. You don’t have the flexibility of deciding whether to enable / disable the Dagger DI on a test by test basis.

2. If you are using the Dagger Android library, then this approach will work with fragments, but not with activities. This is because an AndroidInjector is used in the onCreate() method of the activity to inject the dependencies.

@Override
public void onCreate (Bundle savedInstanceState) {
  AndroidInjection.inject(this);

  super.onCreate(savedInstanceState);
.
.
}

In the next post, I will explore some of the options if we want to mock the ViewModel in the UI tests with Dagger.

Best RxJava Book, so far

These days I tend to read blogs to catch up on the latest programming techniques, although I still read the occasional book. But every now and then I come across a book that is absolutely brilliant, one such as Reactive Programming with RxJava.

This is a great book for learning about RxJava as it goes way beyond just repeating the API and documentation. As well as the usual marble diagrams, the authors help you to take a peek under the hood to explain things like:

  • Use cases about the why and when to use various RxJava constructs.
  • Design decisions about why RxJava does things in certain ways.
  • Comparison with non-Rx and alternative techniques to achieve asynchronous processing, e.g. imperative programming, Futures, manual threading, etc.
  • Integration with existing legacy code and 3rd party libraries.
  • The importance of flatMap operator for asynchronous processing as well as for flattening out nested Observables.

This just scratches the surface in terms of what this book offers, but these were particularly informative for me as a beginner/intermediate RxJava programmer.

Caveat

The reason I put ‘so far’ in the title of this blog is that book documents RxJava 1,  and the downside is that RxJava 2 was released soon after the book was published.

Having said that, most of the contents of the book are still applicable, but you have to mentally translate the concepts and examples to the RxJava 2 API. Hopefully the authors will update the book to RxJava 2 in a future edition.

Groovy and Dagger 2 Android Example

I decided to use the Groovy language for an Android app I was working on. Luckily it was fairly straightforward, but I noticed that the number of blogs and examples available to demonstrate using Groovy for Android development are far fewer than Java ones. Not only that, but many of them were out of date.

This is particularly true if you want to use libraries that are not straightforward coding, such as Dagger 2.

I was intending to write a simple proof-of-concept app to start with, to verify that I could use Dagger 2 and Groovy together. Then I found this example app on Github.

https://github.com/cvoronin/android-groovy-swissknife-dagger2

However this simple Dagger 2 example did now show how to use the @Inject annotation (which is my preferred way to do Dependency Injection into activities), so I created a fork that did.

https://github.com/davidwong/android-groovy-swissknife-dagger2

Note that you will need to use an up-to-date version of Groovy (2.4.x) to get Groovy and Dagger 2 working on Android.

Code Changes

I only had to make a few code changes to use @Inject, you can check the commits in the project to see what they were.

Firstly in the component interface (in the example, it is called demo.simplegroovyapp.component.VehicleComponent), I added a statement that would inject the dependency objects into the activity.


void inject(MainActivity mainActivity)

Then in the activity class (demo.simplegroovyapp.MainActivity) add the @Inject annotation to the field that was to be injected. The other important change I made was to add the public access modifier, I’ll explain later why this is necessary.

In other words, from this:


Vehicle vehicle

to this:


@Inject
public Vehicle vehicle

In the onCreate() method, this line was added to inject the dependencies into the activity.


vehicleComponent.inject(this)

I also commented out the statement that was previously used to manually retrieve the Vehicle object, as it was no longer necessary.


//vehicle = vehicleComponent.provideVehicle()

That’s it!

Property or Field?

In Groovy it is quite common to see data in a class being defined without an access modifier (public, protected, private).


Vehicle vehicle

Likewise in many Dagger 2 Java examples I’ve seen, the @Inject annotation is used on fields without the access modifier.


@Inject

MyPresenter mypresenter;

However when this is done in Groovy, you are specifying a property, not a field.

http://groovy-lang.org/objectorientation.html#_fields_and_properties

Hence Dagger can’t inject the Vehicle object into the activity, even with the @Inject annotation. Once the public access modifier is added, then Dagger works as expected.

 

Protractor Testing with Google Map Markers and Markerclusterers, Part 3

In this final part of this post, we will be locating the cluster markers (from the  Markerclusterer or MarkerclustererPlus library) in a Google map. This is in the context of e2e testing for an AngularJS web application using Protractor.

The first part of the post was a brief introduction , while part 2 showed how to locate Google maps markers.

Markerclusterer

The cluster markers have this DOM structure.

<div class="cluster">
    <img />
    <div>10</div>
</div>

Once again it is just a case of finder the right xpath expression to use as the locator. If we were only interested in the number of cluster markers on the map, we could just use the count() utility method for the ElementArrayFinder as we did for getting a count of the Google maps markers.

element.all(By.xpath("//div[@class=\"cluster\"]/div")).count();

However for the application I was working on, I needed the total number of markers represented by all the cluster markers.

The cluster marker div structure has an inner div that contains a number, this is the number of Google map markers that are not shown but are represented by the cluster. So here we have to get this number from all the cluster markers and add them up.

ElementArrayFinder has various functions such as each() and map() that would allow us to either iterate through the cluster markers and extract the information we need so that we can total the numbers. Luckily it also has a reduce() function that does exactly what we need, and here is an example of a spec test using it.

var checkClusterNumberCount = function(expectedCount) {
    element.all(By.xpath("//div[@class=\"cluster\"]/div")).reduce(function(accum, elem) {
    return elem.getText().then(function(text) {
    var num = parseInt(text);
    return accum + num;
  });
}, 0).then(function(result) {
    expect(result).toEqual(expectedCount);
  });
};

The explanation for this function:

1. The xpath expression is used to locate all the cluster markers in the DOM.

By.xpath(“//div[@class=\”cluster\”]/div”)

2. The function element.all() returns an ElementArrayFinder and the reduce() function is called. In this case it is passed our own reduce function that has 2 parameters:

  • accum holds the accumulated number, which is initially set to zero
  • elem is an ElementFinder from the ElementArrayFinder

3. For each ElementFinder we call the getText() to get the value from the inner div. This value is converted to a number and added to the accumulated number. Notice that since ElementFinder is also a promise, we need to use another callback from the getText() function.

4. We then use the expect() function to compare the final accumulated number to the number that we were expecting in order to pass the test.

Final Tip

Initially after I ran the code to count the markers (both the displayed markers and the ones contained in the cluster markers) I found that, although the code was working properly, some of the tests would occassionally fail. Eventually I worked out that even though in the callbacks the AngularJS code may have finished running, I still sometimes needed to wait for markers and markerclusterers to finish loading in the map.

I worked around this by added a small delay before trying to locate the markers, e.g.
browser.sleep(…);

This is a bit of a hack, but unfortunately I’m not aware of any way to get a notification from Google maps when markers have finished loading.