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!

Share and Enjoy: These icons link to social bookmarking sites where readers can share and discover new web pages.
  • del.icio.us
  • digg
  • DZone
  • Ma.gnolia
  • Reddit
  • Simpy
  • Slashdot
  • StumbleUpon
  • Technorati

6 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.

Leave a Reply