I'd like to unit test my Android application but I found that test driven development in Android is far from trivial at the moment.
Any tips, tricks, war stories for building light weight and preferably fast running tests?
You should try Robotium! Go to Robotium.org [1] and download the example test project. Robotium is a really easy to use framework that makes testing of android applications easy and fast. I created it to make testing of advanced android applications possible with minimum effort. Its used in conjunction with ActivityInstrumentationTestCase2.
[1] http://code.google.com/p/robotium/Also worth checking out is Robolectric [1], an alternative approach to testing Android apps.
Instead of deploying your app and tests to the Android emulator (which can be very slow), Robolectric runs your tests directly in your computer's JVM, reducing typical test turnaround times from minutes to seconds.
Robolectric allows you to test most Android functionality including layouts and GUI behavior, services, and networking code. It offers much greater flexibility than Google's testing framework in testing some Android features, such as widgets and services.
[1] http://robolectric.org/I've been working with Android Unit and Functional tests using the Instrumentation Framework. Its documentation is now clearer than in the past. These links can guide you to start testing:
Introduction to the framework and all related classes:
http://developer.android.com/guide/topics/testing/testing_android.html
A list of these classes:
http://developer.android.com/reference/android/test/package-summary.html
A sample of how to test Activities:
http://developer.android.com/tools/testing/activity_test.html
Looking at ApiDemos sample app, i found ActivityUnitTestCase and ActivityInstrumentationTestCase classes.
Seems that these are utility classes for testing android programs.
Here are the links to the reference:
http://developer.android.com/reference/android/test/ActivityInstrumentationTestCase.html
and
http://developer.android.com/reference/android/test/ActivityUnitTestCase.html
Also android.jar includes a subset of JUnit test framework for plain old unit test. Take a look at ApiDemos sample for learning how to write and run it.
Hope this help!
Three projects aren't necessary (per James answer above). You can get POJO junit 4 tests to run in the Android test project without having the emulator running or device connected. I think the best practice is two projects - one for source, one for tests, and within tests, expect to have tests that are POJO (no android references/emulation required) and tests that require emulation.
But a catch (and a fix)... When I used the Eclipse Android Plugin to "Create a New Android Test Project", Eclipse wouldn't run the junit test with the junit test runner, it will only run them with the Android test runner on the emulator or attached device. Even after I created a new JUnit 4 test and eclipse added Junit 4 jar to the project.
The fix: Go to Run > Run Configurations... Select your Junit test case run config - the one that failed. To the left of Apply it will probably say "Using Eclipse JUnit Test Launcher - Select other...". Even though this seems right, it's not. Click Select other... and choose Android JUnit Test Launcher. Click Run and it should work. If it doesn't, right click on your test case and chose Run As... > JUnit Test. Thanks to Dan Syrstad for the tip.
I believe the initial run config should be Android JUnit Test, but that when you run you can select the JUnit Test config to not require emulation.
And be sure to connect your device for Android unit tests - its WAY faster than the emulator - no start-up time. Very easy to configure - see instructions here:
http://developer.android.com/guide/developing/device.html
Working in android has helped me keep the separation of concerns in order. Keep as much logic out of the view as possible. Follow a common UI design pattern like MVC or MVP. Then that model logic can be unit tested with straight jUnit. I have three projects setup in eclipse.
This doesn't change the fact that using adb shell
to run the Android tests is cumbersome. All I've been able to do is minimize the number of cumbersome tests.
As far as war stories: I was happy to figure out round trip testing the custom Parcelable [1].
[1] http://stuffikeepforgettinghowtodo.blogspot.com/2009/02/unit-test-your-custom-parcelable.htmlFor final integration testing, Robotium [1] is the way to go. However, for detailed coverage and very fast unit testing natively on the development PC (instead of the simulator or on real hardware,) I use PowerMock [2] to mock the Android objects.
I use this in conjunction with Infinitest [3] to enable automatic testing every time I save a file so I can get immediate feedback about whether I have broken anything.
Here's a sample of what my PowerMock unit tests look like:
@RunWith(PowerMockRunner.class)
@PrepareForTest({ TextView.class, EditText.class, Editable.class, Toast.class})
public class NameWasEnteredTest {
@Mock Context context;
@Mock Editable editable;
EditText firstName;
EditText lastName;
Button cancelButton;
Toast toast;
@Test
public void simpleTest() {
NameWasEntered.
nameWasEntered(firstName, lastName, cancelButton, context);
verifyThatFirstAndLastNameEditTextsAreCleared();
verifyThatCancelButtonTextChangedToDone();
verifyThatToastWasShown();
}
private void verifyThatCancelButtonTextChangedToDone() {
verify(cancelButton).setText("Done");
}
private void verifyThatToastWasShown() {
PowerMockito.verifyStatic();
Toast.makeText(eq(context), eq("Name was entered"), anyInt());
}
private void verifyThatFirstAndLastNameEditTextsAreCleared() {
verify(firstName).setText(null);
verify(lastName).setText(null);
}
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
firstName = PowerMockito.mock(EditText.class);
lastName = PowerMockito.mock(EditText.class);
cancelButton = PowerMockito.mock(Button.class);
toast = PowerMockito.mock(Toast.class);
PowerMockito.mockStatic(Toast.class);
when(Toast.makeText(eq(context), anyString(), anyInt())).
thenReturn(toast);
when(firstName.getText()).thenReturn(editable);
when(lastName.getText()).thenReturn(editable);
when(editable.toString()).thenReturn("string");
}
}
Related question [4].
[1] http://code.google.com/p/robotium/I recently released Borachio, a native Scala mocking framework which works on Android.
Because Borachio is written in Scala, you’ll need to write your tests in Scala. But it can be used to test code written in Java.
There's a description of how to use Borachio on Android on my blog:
http://www.paulbutcher.com/2011/03/mock-objects-on-android-with-borachio-part-1/ http://www.paulbutcher.com/2011/03/mock-objects-on-android-with-borachio-part-2/ http://www.paulbutcher.com/2011/03/mock-objects-on-android-with-borachio-part-3/
Aside from easily testing non platform dependent logic I haven't found a clever way to run tests, so far (at least for me) any actual platform logic testing is cumbersome. It's almost non trivial anyway because I've found differences in implementation between the emulator and my actual device and I hate to run a unit test implementation on my device just to remove the application afterwards.
My strategy has been: Try to be concise and make the logic well thought out and then test implementation piece by piece (less then desirable).
Anyone tried the Mockito [1] Framework in conjunction with android development? I always wanted to try it out. It is similar to EasyMock but doesn't depend on interfaces. It seems to create descending classes from your classes under test transparently. The only limitation I'm aware of is testing of final classes and function does not work...
[1] http://mockito.org/I found this presentation over at Slideshare [1] to be helpful.This combined with the blog post over at 8th Light [2] and looking at the unit test examples, scarce as they may be, in the API Demos app helped me to get started doing TDD on my Android app.
[1] http://www.slideshare.net/dtmilano/testing-on-androidStephen Ng provides a good approach for real Unit Test for Android projects solution here:
https://sites.google.com/site/androiddevtesting/
I am fairly new to testing and found Hello, Testing [1] very helpful.
[1] http://developers.androidcn.com/resources/tutorials/testing/helloandroid_test.htmlI recommend using EasyMock extensively for unit testing. I recommend it highly -- the only problem is that somehow on Android (because of some Dalvik VM issues), it can only mock interface classes, and throws errors otherwise. We work around this by creating a TestableClass for every Class that we have, and making that class implement a mock interface that we can test against. I can describe more if people are interested.
Here's a ScreenCast I made on how I got Unit Tests to work. Simple Unit Tests and more complex unit tests that depend on having a reference to Context or Activity objects.
http://www.gubatron.com/blog/2010/05/02/how-to-do-unit-testing-on-android-with-eclipse/
You can also have a look at PowerMock [1] which extends EasyMock and Mockito and allows you to mock e.g. final classes and static methods as well as accessing internal state etc.
[1] http://code.google.com/p/powermock/