Mock objects on Android with Borachio: Part 3

As we saw in part 2 of this series, mocking Android’s PowerManager service directly is impossible. But there is an alternative approach that gives us something close enough. This article describes that approach.

The code of the application described here is checked into GitHub.

Given that we can’t mock PowerManager directly, instead we’re going to create an interface that we can mock:

public interface PowerControl
{
    void disablePowerOff();
    void enablePowerOff();
}

Together with an implementation which will be used in production code:

public class PowerControlImpl implements PowerControl
{
    public PowerControlImpl(Context context) {
        PowerManager powerManager = (PowerManager)
            context.getSystemService(Context.POWER_SERVICE);
        wakeLock = powerManager.newWakeLock(
            PowerManager.FULL_WAKE_LOCK, "PowerControl");
    }

    public void disablePowerOff() {
        wakeLock.acquire();
    }

    public void enablePowerOff() {
        wakeLock.release();
    }

    private PowerManager.WakeLock wakeLock;
}

We won’t be able to test this implementation, but hopefully it’s so simple that (as Hoare puts it) it obviously contains no deficiencies (as opposed to contains no obvious deficiencies).

But we do now have something that we can mock, so we can test that the code that calls it does so correctly.

The first challenge we’re going to have to overcome is how to inject a PowerControl implementation (the real one or the mock) into the code under test. We could use a dependency injection framework like RoboGuice, but for the purposes of this article I’m going to keep things simple and use a custom Application class which implements a getPowerControl method:

public class PowerControlApplication extends Application
{
    public void onCreate() {
        powerControl = new PowerControlImpl(this);
    }

    public PowerControl getPowerControl() {
        return powerControl;
    }

    protected PowerControl powerControl;
}

Our activity calls this during onCreate:

public class PowerActivity extends Activity
{
    @Override
    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        PowerControlApplication app =
            (PowerControlApplication)getApplication();
        powerControl = app.getPowerControl();
    }

    public void startImportant(View button) {
        powerControl.disablePowerOff();
    }

    public void stopImportant(View button) {
        powerControl.enablePowerOff();
    }

    private PowerControl powerControl;
}

We can now write a test to verify that startImportant calls disablePowerOff:

class PowerActivityTest
  extends ActivityUnitTestCase[PowerActivity](classOf[PowerActivity])
  with MockFactory {

  val startIntent = new Intent(Intent.ACTION_MAIN)

  def testStartImportant {
    val mockPowerControl = mock[PowerControl]
    val application = new PowerControlApplication {
      powerControl = mockPowerControl
    }
    setApplication(application)
    startActivity(startIntent, null, null)

    withExpectations {
      mockPowerControl expects 'disablePowerOff once

      getActivity.startImportant(null)
    }
  }
}

Our test first creates a mock PowerControl object:

    val mockPowerControl = mock[PowerControl]

And then creates an application object that returns this mock instead of a “real” PowerControl instance:

    val application = new PowerControlApplication {
      powerControl = mockPowerControl
    }

We tell Android’s test framework to use this application object by calling setApplication:

    setApplication(application)

Finally, we set our expectation (that disablePowerOff is called once) and call startImportant:

    mockPowerControl expects 'disablePowerOff once

    getActivity.startImportant(null)

Updated 2011-04-15

Updated to Borachio 0.6.

6 Responses to “Mock objects on Android with Borachio: Part 3”


  1. 1 Daniel Sobral March 27, 2011 at 12:58 am

    I loved the articles. Now I’m looking for something to do on Android just to put this to use! :-)

  2. 3 Macarse June 17, 2011 at 12:58 pm

    Paul, nice articles and congrats on the work done with Borachio.
    I am giving my first steps with scala so your posts have been great source of information.

    When I finished reading I thought about the following:

    You can’t create a PowerManager object since the constructor is private. Why didn’t you use reflection? Creating an interface for every android class sounds like a lot of pain.

    Also Robolectric has a @RealObject inside every Shadow. Can’t you use that realObject to mock functions?
    jbrechtel just released a scala fw which uses robolectric[1]. You might be interested in taking a look into that.

    Right now I would like to have a test fw for android that allows me to do TDD running tests in the jvm as Robolectric does but also have the opportunity to run this tests in a real environment. What do you think of that?

    Thanks again!

    [1]: https://github.com/jbrechtel/robospecs

  3. 4 paul June 17, 2011 at 3:22 pm

    Hey Carlos,

    It might be possible to use reflection to create an instance of PowerManager (I’ve not tried) but I’m not sure that it would be much of a help. The problem isn’t that we can’t create an instance of it, the problem is that we can’t derive from it (and I’m not aware of any way around that). Yes, we could create an instance and delegate to it, but that’s hardly any easier than creating an interface for every Android class :-)

    I agree that this approach leaves a lot to be desired. That’s why I’m working on an enhancement to Borachio that will (when I’m done!) allow classes with private constructors to be mocked directly (and final classes, static methods, companion objects and a few other “difficult” things). It basically uses a Scala compiler plugin to achieve what PowerMock achieves via cglib. You can read about the beginnings of this here:

    http://www.paulbutcher.com/2011/06/towards-typesafe-native-scala-mocks/

    Robolectric/RoboSpecs is great, but will never allow you to run tests on the device or an emulator. For the kind of things that we do, running on the real device is really essential. I very much hope that the stuff that I’m working on right now will get Borachio to a point where it will enable us to do so more easily.

  4. 5 Glenview Jeff August 25, 2011 at 2:29 pm

    Hi there, and thanks for the great Blog posts re: Scala testing on Android! Your post helped me figure out how to fix the “overloaded method constructor ActivityInstrumentationTestCase2 with alternatives” error I was getting when trying to build a Robotium test.

    In case others stumble upon this post via google, the correct class declaration looks like this:

    class MainActivityTest extends ActivityInstrumentationTestCase2[MainActivity](classOf[MainActivity])


  1. 1 Mock objects on Android with Borachio: Part 2 | Paul Butcher Trackback on March 13, 2011 at 1:17 am

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s





Follow

Get every new post delivered to your Inbox.

Join 241 other followers

%d bloggers like this: