Development of any program is inseparableUnit TestTo ensure its robustness and stability.AndroidThe program is no exception. A mature testing framework has been available since Android SDK 0.9. However, no detailed documentation has been provided for the latest version 1.1, I simply gave several unit test codes in the API demos. Therefore, I will sort out and summarize the content here:
JUnitCan it be used?
InJavaThe unit test will inevitably use JUnit. The JUnit mentioned here refers to a series of unit test functions provided by JUnit. Jar downloaded from the Apache Foundation. These functions are obviously running on JDK. If JDK is no longer available in Android, JUnit cannot be run. However, this does not prevent us from using JUnit to write unit tests. However, when running a unit test, you must use JDK to run and use Java commands to start a runner of JUnit. If you are using eclipse, you can
Create a new JUnit in configuration. But remember to change the android library in Bootstrap entries to jre on the classpath tab and add JUnit. jar.
Obviously, this test is a formal Java unit test, which has nothing to do with Android. You cannot test any APIs in the Android system, activities you write, man-machine interfaces, and so on. Therefore, if you want to test whether it is just an object that encapsulates data, or purely a numerical computation, you can still use this method.
What is the JUnit. Framework Package in Android?
When many people see this package, the first response is whether android has fully integrated JUnit. Unfortunately, this is not a fact. If you follow the running method of JUnit but use JDK instead, you will get an exception:
# # An Unexpected error has been detected by Java Runtime Environment: # # Internal error (classfileparser. cpp: 2924), pid = 4900, tid = 4476 # Error: shouldnotreachhere () # # Java VM: Java hotspot (TM) Client VM (10.0-B19 mixed mode windows-x86) # An error report file with more information is saved: # E: \ mydoc \ eclipseworkspace \ testandroid \ hs_err_pid4900.log # # If you wowould like to submit a bug report, please visit: # Http://java.sun.com/webapps/bugreport/crash.jsp # |
In fact, the testcase class is used to act as the base class of all unique testcase in Android. It is a abstract class. The inheritance diagram of the android unit test class is as follows:
There are so many xxxtestcase mainly to simplifyWork. For exampleDatabaseYou must first start and initialize the database. It is similar here. If you want to test an activity, you must first start it. Activitytestcase will automatically help you complete these tasks. Activityunittestcase will pay more attention to the independence of the test, which will minimize the connection between the test and the android underlying layer. You can view related javadoc for other classes.
To select as needed. To write a test, find the appropriate xxxtestcase as the base class to inherit and write your own test method.
Obviously, the simplest way to write a test is to inherit androidtestcase and write your own testcase. Then, write an activity interface for a group of testcase, which controls the startup, running, and result report of testcase. However, you will soon find out, why do you want to write an interface for the test? This is weird. In this case, a technology is required. It can use shell to start a group of tests and give results in the form of command lines. This is the so-called instrumentation.
What is instrumentation?
Generally, when developing an android program, you need to write a manifest file with the following structure:
<Application Android: icon = "@ drawable/icon" Android: Label = "@ string/app_name"> <Activity Android: Name = ". testapp" Android: Label = "@ string/app_name"> ...... </Activity> </Application> |
In this way, an application is started when the program is started, and then the corresponding activity is loaded during the application running process, and the activity requires an interface. But this is not the case with instrumentation. You can understand instrumentation as a tool class that has no graphical interface and can be started and used to monitor other classes (declared using target package. Any class to be instrumentation must inherit Android. App. instrumentation. The following is an explanation of this class:
"Base class for implementing application instrumentation code. when running with instrumentation turned on, this class will be instantiated for you before any of the application code, allowing you to monitor all of the interaction the system has with
Application. An instrumentation implementation is described to the system through an androidmanifest. XML's <instrumentation> tag."
For unit testing, we need to carefully understand the Android. Test. instrumentationtestrunner class. This is the main entrance to the android unit test. It is equivalent to the role of testrunner in JUnit.
So how to load it, first add a line of statements about instrumentation in the manifest file. For example, the manifest in the test in Android API demos is written like this (I filtered out all comments ):
<Manifest xmlns: Android = "http://schemas.android.com/apk/res/android" Package = "com. example. Android. APIs. Tests"> <Application> <Uses-library Android: Name = "android. Test. Runner"/> </Application> <Instrumentation Android: Name = "android. Test. instrumentationtestrunner" Android: targetpackage = "com. example. Android. APIs" Android: Label = "tests for API demos."/> </Manifest> |
If you use the ADT plug-in of eclipse (version 0.8 or later), you can also use the graphical interface to add the plug-in, such:
After editing the manifest file, you can package it (build, use eclipse ADT, or manually run the aapt command) and install it on the Virtual Machine (use the ADB install command ). Then you can use the command line method to load your unit test. The following command is used to load an instrument in the android shell:
ADB shell am instrument-W xxxxxx
-W indicates the parameter of the specified instrumentation class. A simple example is:
ADB shell am instrument-W com. Android. Foo/Android. Test. instrumentationtestrunner
Of course, you can also use the ADB shell to first enter the android command line mode, and then directly write am instrument-w xxxxxxx. The following describes how to load a group of unit tests as needed.
How to use instrumentation in Android for testing?
Before introducing specific commands, we should first understand the unit test hierarchy. A group of unit tests can be organized into several testsuite instances. Each testsuite contains several testcase (a class that inherits JUnit. Framework. testcase of Android. Jar ). Each testcase contains several test (specific test method ).
Assume that com. Android. foo is the root of your test code package. When the following command is executed, all tests of all testcase are executed. The test object is the code in the package specified in the target package:
ADB shell am instrument-W com. Android. Foo/Android. Test. instrumentationtestrunner
If you want to run a testsuite, first inherit android. jar's JUnit. framework. testsuite class to implement a testsuite (such as COM. android. foo. mytestsuite), and then execute the following command to execute this testsuite
ADB shell am instrument-E Class com. Android. Foo. mytestsuite-W com. Android. Foo/Android. Test. instrumentationtestrunner
-E indicates an additional parameter. The syntax is-E [arg1] [value1] [arg2] [value2]… The class parameter is used here.
If you only want to run a testcase (for example, Com. Android. Foo. mytestcase), run the following command:
ADB shell am instrument-E Class com. Android. Foo. mytestcase-W com. Android. Foo/Android. Test. instrumentationtestrunner
If you only want to run a test (for example, the testfoo method of mytestcase above), it is very similar. Write as follows:
ADB shell am instrument-E Class com. Android. Foo. mytestcase # testfoo-W com. Android. Foo/Android. Test. instrumentationtestrunner
Then, all the test results will be output to the console and a series of statistics will be made. For example, if error is marked as E and failure is marked as F, the success test is marked as a vertex. This is consistent with the meaning of JUnit. If you want to debug your test with a breakpoint, you only need to add the breakpoint directly to the code, and then append-E of the running command parameter with debug true to run it. For more details, see the javadoc of instrumentationtestrunner. I hope android will have a formal document to introduce this content as soon as possible.
How do I mark a unit test in Android?
Several annotations are defined in the Android. Test. annotation package, including @ largetest, @ mediumtest, @ smalltest, @ smoke, and @ suppress. You can use the annotation to classify your tests based on your needs. When executing a unit test command, you can set "size large", "Size medium", and "size small" after the-e parameter to execute a test with corresponding labels. Special @ supperss can cancel the execution of the marked test.
Complete operation process
To sum up all the above content, the following steps are required to compile and run the complete test:
In the above steps, in the example provided by Android, I found that it has two manifest. xml. That is to say, in step 3, the source code and test code generate two different packages respectively. Step 4 Use the ADB install command to install it on the virtual machine. Since I didn't find eclipse ADT, there is a way to package and install an application with only instrumentation and no activity, so I used a slightly different method to complete this work. The entire process is described in detail in the following sections.
1. Write a program
I created a project testapp with the following parameters:
Package name: COM. Android. testapp Activity name: mainactivity Application name: testapp |
The source code of mainactivity is as follows:
PackageCom. Android. testapp; ImportAndroid. App. activity; ImportAndroid. OS. Bundle; PublicclassMainactivityExtendsActivity { /** Called when the activity is first created .*/ @ Override PublicvoidOncreate (bundle savedinstancestate ){ Super. Oncreate (savedinstancestate ); Setcontentview (R. layout.Main); } PublicintSum (IntA,IntB ){ ReturnA + B; } PublicintSubstract (IntA,IntB ){ ReturnB-; } } |
Specifically, I intentionally wrote the subtraction a-B as B-.
2. Compile the test program
Then, I created a new source folder named test and created the com. Android. testapp. Test package in it. A testcase named testmainactivity is defined. The source code is as follows:
PackageCom. Android. testapp. test;
ImportCom. Android. testapp. mainactivity; ImportAndroid. Test. activityinstrumentationtestcase; ImportAndroid. Test. suitebuilder. annotation. mediumtest; Public classTestmainactivityExtendsActivityinstrumentationtestcase <mainactivity> { PublicTestmainactivity (){ Super("Com. Android. testapp", mainactivity.Class); } PublicTestmainactivity (string PKG, class <mainactivity> activityclass ){ Super(PKG, activityclass ); } @ Mediumtest Public voidTestsum (){ Assertequals(3, getactivity (). sum (1, 2 )); } @ Mediumtest Public voidTestsubstract (){ Assertequals(-1, getactivity (). substract (1, 2 )); } } |
I inherited activityinstrumentationtestcase. This testcase will automatically start the corresponding activity for me during execution.
Next is the manifest of the program:
<? XML version ="1.0"Encoding ="UTF-8"?> <Manifest xmlns: Android =Http://schemas.android.com/apk/res/android" Package ="Com. Android. testapp" Android: versioncode ="1" Android: versionname ="1.0.0"> <Application Android: icon ="@ Drawable/icon"Android: Label ="@ String/app_name"> <Activity Android: Name =". Mainactivity" Android: Label ="@ String/app_name"> <Intent-filter> <Action Android: Name ="Android. Intent. Action. Main"/> <Category Android: Name ="Android. Intent. Category. launcher"/> </Intent-filter> </Activity> <Uses-library Android: Name ="Android. Test. Runner"/> </Application> <Instrumentation Android: targetpackage ="Com. Android. testapp"Android: Name ="Android. Test. instrumentationtestrunner"Android: Label ="Test Unit Tests"> </Instrumentation> </Manifest> |
In this file, I write the declaration of activity and instrumentation together, instead of separating them like Apis demo. Note the <uses-library> label. If there is no such sentence, the testrunner will not be found during the test. This is because Android only packs the required items during build, so you must clearly tell Android builder this.
3. Build and install
In eclipse, these two steps are completed together. Just click Run. However, if you do not set the launch action after installation to "do nothing" in the run configuration, your mainactivity will be automatically run. For us, set it to do nothing. For example:
Then, run the following command:
ADB shell PM list packages
You can see COM. Android. testapp in the installed PKG list.
4. Run the test and view the result.
Then open the command line and run the following command
ADB shell am instrument-E Class com. Android. testapp. Test. testmainactivity-W com. Android. testapp/Android. Test. instrumentationtestrunner
You can see the following results:
We can see that the unit test correctly found the error in subtraction. "." Is displayed for a successful test in the result, and "F" is displayed for a failed test ". However, I still don't quite understand why I only wrote two test methods, but tests run showed 3.