Android单元測试之JUnit

       随着近期几年測试方面的工作慢慢火热起来。常常看见有招聘測试project师的招聘信息。在Java中有单元測试这么一个JUnit

方式,Android眼下主要编写的语言是Java,所以在Android开发中也会有那么一个单元測试---JUnit。从Android的开发环境搭建可

以看出来,Android先要在JDK的基础上,然后导入Android自己的SDK开发环境,当然Android的单元測试JUnit是专门測试Android

 APP里面的方法性能等。Android最常见的測试----JUnit。Android提供了一系列强大的測试工具,它针对Android的环境。扩展了

业内标准的JUnit測试框架。

虽然你能够使用JUnit測试Androidproject,但Android工具同意你为应用程序的各个方面进行更为复杂的

測试。包含单元层面及框架层面。


一、Android測试环境的主要特征有:
 1、能够訪问Android系统对象。
 2、Instrumentation框架能够控制和測试应用程序。
 3、Android系统经常使用对象的模拟版本号。
 4、执行单个test或test suite的工具,带或不带Instrumentation。
 5、支持以Eclipse的ADT插件和命令行方式管理Test和Testproject。


二、JUnit核心框架-----Instrumentation框架:

     Android測试环境的核心是一个Instrumentation框架,在这个框架下,你的測试应用程序能够精确控制应用程序。使用Instrumentation。你能够在主程序启动之前,创建模拟的系统对象。如Context。控制应用程序的多个生命周期;发送UI事件给应用程序;在执行期间检查程序状态。Instrumentation框架通过将主程序和測试程序执行在同一个进程来实现这些功能。
    通过在測试project的manifest文件里加入<instrumentation>元素来指定要測试的应用程序。这个元素的特性指明了要測试的应用程序包名,以及告诉Android怎样执行測试程序。
 在Android中,測试程序也是Android程序。因此。它和被測试程序的书写方式有非常多同样的地方。

SDK工具能帮助你同一时候创建主程序project及它的測试project。

你能够通过Eclipse的ADT插件或者命令行来执行Android測试。Eclipse的ADT提供了大量的工具来创建測试用例。执行以及查看结果。

       首先,我们来了解一下android的測试类的层次结构:

         

     Testing API
          Android提供了基于JUnit測试框架的測试API来书写測试用例和測试程序。

另外,Android还提供了强大的Instrumentation框架。同意測试用例訪问程序的状态及执行时对象。

    JUnit TestCase类
          继承自JUnit的TestCase,不能使用Instrumentation框架。

但这些类包括訪问系统对象(如Context)的方法。使用Context。你能够浏览资源,文件,数据库等等。基类是AndroidTestCase,一般常见的是它的子类,和特定组件关联。

      子类有:

        1、ApplicationTestCase——測试整个应用程序的类。它同意你注入一个模拟的Context到应用程序中,在应用程序启动之前初始化測试參数,并在应用程序结束之后销毁之前检查应用程序。


        2、ProviderTestCase2——測试单个ContentProvider的类。

由于它要求使用MockContentResolver,并注入一个IsolatedContext。因此Provider的測试是与OS孤立的。
        3、ServiceTestCase——測试单个Service的类。你能够注入一个模拟的Context或模拟的Application(或者两者),或者让Android为你提供Context和MockApplication。

    Instrumentation TestCase类
         继承自JUnit TestCase类,并能够使用Instrumentation框架。用于測试Activity。

使用Instrumentation,Android能够向程序发送事件来自己主动进行UI測试。并能够精确控制Activity的启动,监測Activity生命周期的状态。

基类是InstrumentationTestCase。

它的全部子类都能发送按键或触摸事件给UI。子类还能够注入一个模拟的Intent。

   子类有:
1、 ActivityTestCase——Activity測试类的基类。


2、 SingleLaunchActivityTestCase——測试单个Activity的类。它能触发一次setup()和tearDown()。而不是每一个方法调用时都触发。假设你的測试方法都是针对同一个Activity的话。那就使用它吧。
3、 SyncBaseInstrumentation——測试Content Provider同步性的类。

它使用Instrumentation在启动測试同步性之前取消已经存在的同步对象。
4、ActivityUnitTestCase——对单个Activity进行单一測试的类。

使用它。你能够注入模拟的Context或Application,或者两者。它用于对Activity进行单元測试。


不同于其他的Instrumentation类,这个測试类不能注入模拟的Intent。
5、 ActivityInstrumentationTestCase2——在正常的系统环境中測试单个Activity的类。

你不能注入一个模拟的Context。但你能够注入一个模拟的Intent。

另外,你还能够在UI线程(应用程序的主线程)执行測试方法。而且能够给应用程序UI发送按键及触摸事件。


三、Instrumentation框架的測试使用方法

       Instrumentation和Activity有点类似,仅仅只是Activity是须要一个界面的。而Instrumentation并非这种,我们能够将它理解为一种没有图形界面的。具有启动能力的,用于监控其它类(用Target Package声明)的工具类。

       以下通过一个简单的样例来解说Instrumentation的基本測试方法。

          1.首先建立一个Android project,类名为Sample,代码例如以下:
public class Sample extends Activity {
   private TextView myText = null;
   private Button button = null;
 
   @Override
   public void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       setContentView(R.layout.main);
       myText = (TextView) findViewById(R.id.text1);
       button = (Button) findViewById(R.id.button1);
       button.setOnClickListener(new OnClickListener() {
           @Override
           public void onClick(View arg0) {
               myText.setText("Hello Android");
           }
       });
   }
 
   public int add(int i, int j) {
       return (i + j);
   }
}
这个程序的功能比較简单。点击button之后,TextView的内容由Hello变为Hello Android.同一时候。在这个类中。我还写了一个简单的add方法。没有被调用,仅供測试而已。

      2. 在src目录中加入一个測试包。在測试包中加入一个測试类SampleTest
測试类的代码例如以下:
public class SampleTest extends InstrumentationTestCase {
   private Sample sample = null;
   private Button button = null;
   private TextView text = null;
 
   /*
    * 初始设置
    * @see junit.framework.TestCase#setUp()
    */
   @Override
   protected void setUp()  {
       try {
           super.setUp();
       } catch (Exception e) {
           e.printStackTrace();
       }
       Intent intent = new Intent();
       intent.setClassName("com.hustophone.sample", Sample.class.getName());
       intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
       sample = (Sample) getInstrumentation().startActivitySync(intent);
       text = (TextView) sample.findViewById(R.id.text1);
       button = (Button) sample.findViewById(R.id.button1);
   }
 
   /*
    * 垃圾清理与资源回收
    * @see android.test.InstrumentationTestCase#tearDown()
    */
   @Override
   protected void tearDown()  {
       sample.finish();
       try {
           super.tearDown();
       } catch (Exception e) {
           e.printStackTrace();
       }
   }
 
   /*
    * 活动功能測试
    */
   public void testActivity() throws Exception {
       Log.v("testActivity", "test the Activity");
       SystemClock.sleep(1500);
       getInstrumentation().runOnMainSync(new PerformClick(button));
       SystemClock.sleep(3000);
       assertEquals("Hello Android", text.getText().toString());
   }
 
   /*
    * 模拟button点击的接口
    */
   private class PerformClick implements Runnable {
       Button btn;
       public PerformClick(Button button) {
           btn = button;
       }
 
       public void run() {
           btn.performClick();
       }
   }
   /*
    * 測试类中的方法
    */
   public void testAdd() throws Exception{
       String tag = "testAdd";
       Log.v(tag, "test the method");
       int test = sample.add(1, 1);
       assertEquals(2, test);
   }
}

       以下来简单解说一下代码:
setUp()和tearDown()都是受保护的方法。通过继承能够覆写这些方法。


          在android Developer中有例如以下的解释
       protected void setUp ()
Since: API Level 3
Sets up the fixture, for example, open a network connection. This method is called before a test is executed.
                protected void tearDown ()
Since: API Level 3
Make sure all resources are cleaned up and garbage collected before moving on to the next test. Subclasses that override this method should make sure they call super.tearDown() at the end of the overriding method.

setUp ()用来初始设置。如启动一个Activity,初始化资源等。
tearDown ()则用来垃圾清理与资源回收

在testActivity()这个測试方法中。我模拟了一个button点击事件。然后来推断程序是否依照预期的运行。在这里PerformClick这种方法继承了Runnable接口,通过新的线程来运行模拟事件,之所以这么做。是由于假设直接在UI线程中运行可能会阻滞UI线程。

       2.要想正确地运行測试,还须要改动AndroidManifest.xml这个文件.
          <!--用于引入測试库-->
                <uses-library android:name="android.test.runner" />
                <activity android:name=".Sample" 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-sdk android:minSdkVersion="3" />
        <!--表示被測试的目标包与instrumentation的名称。-->
         <instrumentation android:targetPackage="com.hustophone.sample"                                                                   android:name="android.test.InstrumentationTestRunner" />

        经过以上步骤,以下能够開始測试了。測试方法也有以下几种,以下介绍两个经常使用的方法:

       (1) 用Eclipse集成的JUnit工具
               在Eclipse中选择projectSample,单击右键。在Run as子菜单选项中选择Android JUnit Test
    


同一时候能够通过LogCat工具查看信息


 

        (2) 通过模拟器执行单元測试

            点击模拟器界面的Dev Tools菜单

           再点击Instrumentation选项。进入Instrumentation菜单


                  


          这里有一个InstrumentationTestRunner,它是測试的入口。点击这个选项,就能够自己主动执行我们的測试代码。下面为执行结果:

       button点击前

       button点击后
  

至此,一个简单的測试过程结束了。当然。android的測试内容还有非常多,也有比較复杂的,我会在以后的学习过程中继续分享我的体会。

好了。今天就到这里吧!


原文地址:https://www.cnblogs.com/mengfanrong/p/5220061.html