12

I have a Java library that uses a few things from the Android APIs. I'd like to use Mockito to write unit tests for this library.

Is there a way I can go about this?

Mockito doesn't play nice on the Dalvik VM, see this post: Using Mockito with Android virtual machine

UPDATE:

Since this post I've discovered Robolectric, and I've had the opportunity to work out of Pivotal Labs and make some small contributions to this library. I would recommend using this over the Android testing framework/mockito. Also, you're free to use Robolectric AND Mockito, but the shadow objects in Robolectric make Mockito unnecessary for most use cases.

The problem with trying to unit test Android is that the Android library that you build on has every method stubbed out to either throw a stub exception, or return null. If you want to test your app and want any Android behavior you are out of luck, unless you use Robolectric which rewrites the byte-code on the fly when the classes load, and injects a shadow object that simulates the behavior.

UPDATE 2:

It's been a while and things have changed. Many of the Shadow classes in Robolectric have been replaced with the real Android classes. The real Android jars are now used and Robolectric only loads Shadow classes for a much smaller set of things. This is even more of a reason to use Robolectric for your Android testing.

Christopher Perry
  • 38,891
  • 43
  • 145
  • 187

4 Answers4

9

After much Googling, I have come across an answer for this here.

Basically it involves using the Robolectric unit testing framework, which intercepts the loading of the Android classes. You can then go ahead and use Mockito (although it isn't necessary in most cases) and run your tests on the JVM!

xverges
  • 4,608
  • 1
  • 39
  • 60
Christopher Perry
  • 38,891
  • 43
  • 145
  • 187
  • I use the Spy-construct from Mockito in combination with the builders provided by Robolectric. That way I can do partial mocking of the android components when needed, e.g. FooActivity foo = spy(Robolectric.buildActivity(FooActivity.class).get()); doReturn(mock).when(foo).getSomething(); – Alix Aug 31 '15 at 22:10
2

As of version 1.9.5 (released 3rd of June, 2012) you can use Mockito with Android. To do this you will also require dexmaker:

http://code.google.com/p/dexmaker/

This wiki page describes how to implement it:

http://code.google.com/p/dexmaker/wiki/Mockito

Ian Newson
  • 7,679
  • 2
  • 47
  • 80
  • This doesn't give you any Android behavior. Robolectric is still the best choice, since it provides Mocks (the shadow classes) and Android behavior. – Christopher Perry Jun 19 '12 at 16:28
  • 2
    I understand, but your question was not 'what is the best mocking framework for Android' but 'how can I use Mockito with Android'. – Ian Newson Jun 19 '12 at 16:47
  • @ChristopherPerry I think there may be some confusion actually. Using Mockito in this way with the Android testing framework and JUnit means your tests run on an actual device or the emulator, meaning all of the Android classes are available. The Android testing framework also provides built in mocks, such as `MockContext`. – Ian Newson Jun 20 '12 at 05:54
  • Yes but the Android testing framework is terrible. I updated the question to reflect the overall thread. – Christopher Perry Jun 20 '12 at 17:08
  • @ChristopherPerry you've updated your question when really your edit should be a separate answer (as it already is). This seems like poor etiquette. – Ian Newson Jun 20 '12 at 17:22
1

Take a look at android-mock. It's based on EasyMock 2.4 (so not quite as nice as Mockito but close).

It gets around the limitations of the DalvikVM by pre-generating the mock classes at build time rather than runtime, and then bunding them with your compiled test code when deploying to the device.

There's also a mocking framework called Borachio which I can't vouch for but looks promising (if you're happy to go through the motions of getting Scala to run on your device).

tomato
  • 3,373
  • 1
  • 25
  • 33
1

You can avoid it, for everything that has nothing to do with the Android SDK internal classes. That's what I'm doing for my Android projects (although I use JMock2, not Mockito).

I have two test projects.

  • The first one uses JUnit4 and JMock2 that I added myself as dependencies. I test all the "business logic" classes, but I can't test anything that has to do with Android (UI classes, SQLiteOpenHelper, etc.) If I try to use them in my tests, I get the dreaded Stub! exception.

  • The second one to test the UI, using ActivityInstrumentationTestCase2 and Robotium.

That may seem like a lot of work and complex, but really it's not, and I actually think it's better to separate them. UI tests are not "real" unit-tests and they often test some features across multiple units. If you properly separate your UI layer from your business logic (and doing this separation of tests will force you to do that, in TDD style), then it's all nice and smooth.

Guillaume
  • 22,694
  • 14
  • 56
  • 70
  • Sigh. The problem is that my business model classes use AsyncTask to grab every piece of data I'm using in the app, on every page. I was thinking, since AsyncTask is basically a POJO that I could just grab the code for it and put it in my project and lose the dependency. – Christopher Perry Nov 13 '11 at 19:00
  • If I were you, I would try to abstract out all the Android dependencies to interfaces, so that the Stub don't get in the way. Probably not as easy as it sounds with AsyncTask though... – Guillaume Nov 13 '11 at 19:36
  • @Chirstopher Perry: Did you get some solution of your problem to test ASync Tasks effectively? I'm kinda in the same boat now. – bianca Mar 16 '13 at 22:07