Tuesday, December 2, 2008

Instrumentation and JUnit

JUnit has been nicely integrated into Android. JUnit classes are specialized to facilitate common Android testing tasks. In this post, I will talk about my experiences with InstrumentationTestRunner and the facilities it provides to integrate Android instrumentation with JUnit test execution.

As we have seen previously, the difficulty in JUnit-instrumentation integration stems from the fact that an instrumentation is an entire Android application, started, managed and terminated for testing purposes. One has to work quite a bit to make sure that the test controller is not terminated along with the application under test. InstrumentationTestRunner solves this problem by launching the Dalvik VM in special, instrumentation mode.

You can download the example program from here.

The test subject is our well known Calculator program that was renamed as Calculator2 so that we do not confuse it with the version coming from previous application packages, other than that it is the same simple program. Under aexp.calculator.tests, you will find two JUnit test classes. There are things to note, however.
  • Instead of TestCase, the test classes inherit from ActivityInstrumentationTestCase, templated by the activity class under test.
  • The constructor of the test class defines the activity under test class precisely.
One such test class or collection of test classes can be executed by InstrumentationTestRunner. Execute the following command (from command prompt).

adb shell am instrument -w aexp.calculator/android.test.InstrumentationTestRunner

The console of the command prompt reads like this:

aexp.calculator.tests.AddFunctionalTests:...
aexp.calculator.tests.SubFunctionalTests:...
Test results for InstrumentationTestRunner=......
Time: 11.448

OK (6 tests)

Meanwhile, the emulator main window flashes with action. Calculator2 is launched 4 times, each time the key input is automatically provided by the test case. All this is arranged by the Android specialization of TestCase/TestRunner.

Please observe the AndroidManifest.xml of the project. Check out the uses-library tag and the use of instrumentation tag, particularly the targetPackage attribute that refers to the application package under test (and not the Java package name of the test classes). InstrumentationTestRunner automagically looks for test classes that fit the test execution criteria (again, check out InstrumentationTestCase documentation for options), there was no need to organize the test classes into suites.

Note that the arrangement of this project is not typical. I mixed the test classes and the activity under test into the same application. This eliminates a lot of deployment problems that caused so much trouble for so many people when playing with the Android test framework. The typical deployment, however, is to place the test classes and application under test into separate application packages. I will get to that in the next post.

9 comments:

ele said...

I cannot download your example code:( Is it the same as android_sourcecode\packages\apps\Calculator\tests ?

Raj said...

Hi,

I have tried to execute your code...

But can you tell me what is that bild.xml file

for what we are using that...

You didn't mentioned anyting about that.....

wipraj said...

Hi Gabor,

See the resulst your totally having 4 tests 2 from Addtes and 2 from Subtest. But the result showing totally 6 tests executed successfully.. So tell me wht its showing 6.. and If I use something in Setup and tearDown its also get executing 6 times....

One test excuting twice...

So please chieck it....

Anonymous said...

ActivityInstrumentationTestCase has been deprecated.

ActivityInsutrmentationTestCase2 has replaced it.

Anonymous said...

$ adb shell am instrument -w aexp.calculator/android.test.InstrumentationTestRunner
INSTRUMENTATION_STATUS: id=ActivityManagerService
android.util.AndroidException: INSTRUMENTATION_FAILED: aexp.calculator/android.test.InstrumentationTestRunnerINSTRUMENTATION_STATUS: Error=Unable to find instrumentation info for: ComponentInfo{aexp.calculator/android.test.InstrumentationTestRunner}
INSTRUMENTATION_STATUS_CODE: -1

veena said...

Hello,

I am new to this area and would really appreciate if someone could point me in the right direction. I am using the selenium driver on Android ( AndroidDriver ). The way I understand that it works is there is a server component that runs on jetty. When I deploy my androidjunit test through Eclipse, Eclipse takes care of transferring the .apk file onto the device and tests the AndroidDriver on the device. So I have actually got the test case mentioned in this link http://code.google.com/p/selenium/wiki/AndroidDriver working. What I want to know is, Is there a way that I could deploy this testcase as an application on the phone. So whenever a user wants to test the selenium WebDriver application, all he needs to do is start an application on the phone that will launch the test case for him.

One idea we could think of was to do that from a web page. We open a Web browser on the phone, we go to a web page where there is a link to the client runtime application and maybe with a bit of Javascript, it downloads the app and puts it in Jetty.

Any help is deeply appreciated.

Thanks

veena said...

Hello,

I am new to this area and would really appreciate if someone could point me in the right direction. I am using the selenium driver on Android ( AndroidDriver ). The way I understand that it works is there is a server component that runs on jetty. When I deploy my androidjunit test through Eclipse, Eclipse takes care of transferring the .apk file onto the device and tests the AndroidDriver on the device. So I have actually got the test case mentioned in this link http://code.google.com/p/selenium/wiki/AndroidDriver working. What I want to know is, Is there a way that I could deploy this testcase as an application on the phone. So whenever a user wants to test the selenium WebDriver application, all he needs to do is start an application on the phone that will launch the test case for him.

One idea we could think of was to do that from a web page. We open a Web browser on the phone, we go to a web page where there is a link to the client runtime application and maybe with a bit of Javascript, it downloads the app and puts it in Jetty.

Any help is deeply appreciated.

Thanks

Anonymous said...

Hi I have download your code and run it using command
>
adb shell am instrument -w aexp.calculator.tests/android.test.InstrumentationTestRunner

Getting error
INSTRUMENTATION_STATUS: id=ActivityManagerService
INSTRUMENTATION_STATUS: Error=Unable to find instrumentation info for: Component
Info{aexp.calculator.tests/android.test.InstrumentationTestRunner}
INSTRUMENTATION_STATUS_CODE: -1
android.util.AndroidException: INSTRUMENTATION_FAILED: aexp.calculator.tests/and
roid.test.InstrumentationTestRunner
at com.android.commands.am.Am.runInstrument(Am.java:616)
at com.android.commands.am.Am.run(Am.java:118)
at com.android.commands.am.Am.main(Am.java:81)
at com.android.internal.os.RuntimeInit.nativeFinishInit(Native Method)
at com.android.internal.os.RuntimeInit.main(RuntimeInit.java:235)
at dalvik.system.NativeStart.main(Native Method)

Is there any setting done in Eclipse?

Gabor Paller said...

Anonymous, the application has to be installed first. What I did (in Eclipse) is that I exported the application APK (Export/Export Android application) then I installed it from the command prompt (adb install Calculator.apk). Then I could run the command in the post. Take care, it is not "... -w aexp.calculator.tests/android.test.InstrumentationTestRunner", just "... -w aexp.calculator/android.test.InstrumentationTestRunner"