a little madness

A man needs a little madness, or else he never dares cut the rope and be free -Nikos Kazantzakis

Zutubi

Android Functional Testing vs Dependency Injection

I commonly use Dependency Injection (DI) to create testable Java code. Dependency injection is simple: instead of having your objects find their own dependencies, you pass them in via the constructor or a setter. One key advantage of this is the ability to easily substitute in stub or mock dependencies during testing.

Naturally, as I started working on an Android application, I tried to apply the same technique. Problems arose when I tried to combine DI with the Android SDK’s Testing and Instrumentation support. In particular, I am yet to find a suitable way to combine DI with functional testing of Android activities via ActivityInstrumentationTestCase2. When testing an activity using the instrumentation support, injection of dependencies is foiled by a couple of factors:

  1. Constructor injection is impossible, as activities are constructed by the framework. I experimented with various ways of creating the Activity myself, but was unable to maintain a connection with the Android system for true functional testing.
  2. Setter injection is fragile, as activities are started by the framework as soon as they are created. There is no time to set stub dependencies between the instantiation of the Activity and its activation.

Not ready to give DI away, I scoured the web for existing solutions to this problem. Although I did find some DI libraries with Android support (notably Guice no AOP and roboguice which builds upon it), the only testing support I found was restricted to unit tests. Although roboguice has support for Activities, it relies on being able to obtain a Guice Injector from somewhere — which just shifts the problem by one level of indirection.

Given how complex any DI solution was going to become (if indeed it is possible at all) I decided to step back and consider alternatives. A classic alternative to DI is the Service Locator pattern: where objects ask a central registry for their dependencies. Martin Fowler’s article Inversion of Control Containers and the Dependency Injection pattern compares and contrasts the two patterns in some detail. Most importantly: a Service Locator still allows you to substitute in different implementations of dependencies at test time. The main downside is each class is dependent on the central registry — which can make them harder to reuse. As I’m working with Activities that are unlikely to ever be reused outside of their current application, this is no big deal.

Implementation-wise, I went with the simplest registry that works for me. I found it convenient to use my project’s Application implementation as the registry. In production, the Application onCreate callback is used to create all of the standard dependency implementations. These dependencies are accessed via simple static getters. Static setters are exposed to allow tests to drop in whatever alternative dependencies they desire. A contrived example:

public class MyApplication extends Application
{
    private static IService service;
    private static ISettings settings;

    @Override
    public void onCreate()
    {
        super.onCreate();
        if (service == null)
        {
            service = new ServiceImpl();
        }
        
        if (settings == null)
        {
            SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
            settings = new PreferencesSettings(preferences);
        }
    }
    
    public static IService getService()
    {
        return service;
    }

    public static void setService(IService s)
    {
        service = s;
    }
    
    public static ISettings getSettings()
    {
        return settings;
    }
    
    public static void setSettings(ISettings s)
    {
        settings = s;
    }
}

I access the dependencies via the registry in my Activity’s onCreate callback:

public class MyActivity extends Activity
{
    private IService service;
    private ISettings settings;

    @Override
    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);

        service = MyApplication.getService();
        settings = MyApplication.getSettings();

        setContentView(R.layout.main);
        // ...
    }

    // ...
}

And I wire in my fake implementations in my functional test setUp:

public class MyActivityTest extends ActivityInstrumentationTestCase2<MyActivity>
{
    private MyActivity activity;

    public MyActivityTest()
    {
        super("com.zutubi.android.example", MyActivity.class);
    }

    @Override
    protected void setUp() throws Exception
    {
        super.setUp();        
        MyApplication.setService(new FakeService());
        MyApplication.setSettings(new FakeSettings());
        activity = getActivity();
    }
    
    public void testSomething() throws Throwable
    {
        // ...
    }

After all of the angst over DI, this solution is delightful in its simplicity. It also illustrates that static is not always a dirty word when it comes to testing!

Liked this post? Share it!

14 Responses to “Android Functional Testing vs Dependency Injection”

  1. June 30th, 2010 at 6:27 am

    Manfred Moser says:

    Does that not make your application class pretty heavy? Does that affect startup time for you?

  2. June 30th, 2010 at 7:13 am

    Dominic Mitchell says:

    An alternative might be to look at android-mock. This is a port of easymock to android, which may be useful in cases where swapping in and out fakes manually in setUp() is tedious.

    http://code.google.com/p/android-mock/

  3. June 30th, 2010 at 11:06 am

    Jason says:

    Hi Manfred,

    This is a good point. In my case the app is quite small, and the dependencies are cheap to initialise, so I don’t see any problems with startup time. However, in many cases it would be wise to delay intialisation of some services until they are required (which could be as simple as checking and initialising as required in the getter).

  4. June 30th, 2010 at 11:08 am

    Jason says:

    Hi Dom,

    Thanks for the tip: I’ll have to check out android-mock.

  5. July 13th, 2010 at 9:47 pm

    Miguel says:

    Hi,

    have you tested any Activity that made changes on the preferences? In my tests, the changes were persistent, which is something I obviously don’t want. I’m still new to android world, but my guess is that getContext() returns the real context of the application rather than a mock/fake one.

    Thanks a lot for the android related posts, they are well written and formative. I added you to my reader.

  6. July 13th, 2010 at 10:48 pm

    Jason says:

    Hi Miguel,

    Thanks for the kind feedback. Re: testing preferences, you are correct that if you use ActivityInstrumentationTestCase2 you get a real context and changes to the preferences will persist. Actually in my example I use an interface (ISettings) in between the preferences and my activity under test. In my case this is to make it easy for me to fake different preferences without changing the underlying persistent data. You could extend this idea to allow settings to be changed via the ISettings interface, and test your activity makes the intended updates in that way.

  7. January 4th, 2011 at 7:51 am

    David Laing says:

    Jason,

    Amazing – a pattern that usually gets me in trouble is exactly right for a simple Android app.

    Thanks for bringing it to my attention (again)

    David

  8. January 13th, 2011 at 5:07 pm

    Yoshihiro says:

    Hi.

    I tried to inject to Activity by using guice2.0_no_AOP.I didn’t use roboguice.

    I could inject by field static injection like following.

    //MyActivity
    public class MyActivity …
    @Inject static private Service service;

    //in guice Module
    Protected void configure() {
    bind(Service.class).to(ServiceImpl.class);
    requestStaticInjection(MyActivity.class);
    }

    But when I write test, using this method let me write another Module for test and make injector instance in testing code.

    Do you think which one is easier?

  9. April 18th, 2011 at 5:25 am

    Tom Leach says:

    Great pattern! Having come from an enterprise background and being used to making heavy use of DI I was a bit dismayed to find out how coupled android application classes seem to be to the underlying API via inheritance.

    I had considered roboguice as a possibility but I don’t like the way it makes you use their testing framework classes.

    Using a centralised service locator seems like a good pragmatic alternative. I’ll give it a go.

  10. September 7th, 2011 at 2:30 pm

    Sam says:

    I use a similar pattern although I initialise the service to the default impl as required via null check and just use the setter in the tests.
    However, my issue is that my fake service is providing an alternative data set which cannot be browsed via the running app (when conceiving a new test) without the app knowing about the fake class.. which it doesn’t because it resides in the test application, not the application. Do you know how to run the android app in “test mode” .. ie, as you would see it when the unit tests are run against the fake service?

  11. October 20th, 2011 at 3:36 am

    Tom says:

    You can actually make it work with instance rather than static fields if the test uses getInstrumentation().getTargetContext().getApplicationContext() to get a reference to the application object.

  12. November 22nd, 2011 at 11:16 pm

    Dan says:

    This post just blew my mind. As a newb Android developer (two months) I have been looking for a good way to do this. This is awesome!

    Thanks for the wonderful post!

  13. January 11th, 2012 at 11:05 am

    Maks says:

    Thanks for the great pattern, its a perfect fit for use in simple android apps and exactly what I was after without going the heavy weight route of using roboguice.

  14. February 24th, 2012 at 4:28 am

    Cassio Landim says:

    Nice! Thanks!

Leave a Reply