`
wen742538485
  • 浏览: 241367 次
  • 性别: Icon_minigender_1
  • 来自: 广州
社区版块
存档分类
最新评论

Android 下junit 作单元测试

阅读更多
http://mintelong.javaeye.com/blog/460903



   在 Java下做单元测试必然用到JUnit。这里说的JUnit是指从Apache基金会下载的junit.jar里提供的一系列单元测试功能。这些功能显然是运行在JDK之上的。在Android下已经没有了JDK,自然也无法运行JUnit。但是这并不妨碍我们利用JUnit编写单元测试。只不过在运行单元测试时,一定要用JDK来运行,利用java命令来启动JUnit的某个Runner。如果是用Eclipse的话,可以在Run Configuration里新建一个JUnit。但是一定要记得在Classpath选项卡里将Bootstrap Entries中的Android Library改成JRE,并且添加junit.jar。


  很明显的,这种测试就是正规的Java单元测试,和Android没有任何关系。你无法测试任何关于Android系统中的API,你写的Activity,人机界面等等。所以,如果你想测试仅仅是一些封装数据的对象,或者是纯粹的数值计算,还是可以用这种方法的。

  Android里面的junit.framework包是怎么回事?

  很多人看到这个包的时候,第一反应是Android是不是已经完整集成了JUnit。很遗憾这不是事实。如果你按照JUnit的运行方法,却不像上面那样改用JDK,就一定会得到一个异常:

  #

  # 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 as:

  # E:\Mydoc\EclipseWorkspace\TestAndroid\hs_err_pid4900.log

  #

  # If you would like to submit a bug report, please visit:

  #http://java.sun.com/webapps/bugreport/crash.jsp

  #

  实际上,TestCase这个类用于在Android担当所有独特的TestCase的基类的作用,它是一个Abstract Class。Android单元测试类继承关系图如下所示:


  之所以有那么多XXXTestCase主要是为了简化工作。例如当你想对一个访问数据库的功能进行测试时,首先需要自己启动并初始化数据库。在这里是类似的,如果你想测试一个Activity,首先要启动它。而ActivityTestCase就会自动帮你做完这些事情。而 ActivityUnitTestCase会更注重测试的独立性,它会让测试与Android底层的联系降到最低。其余的类可以查看相关的Javadoc 来按需挑选。要编写测试,就是找到合适的XXXTestCase作为基类来继承,并且编写自己的测试方法。

  很明显的,最简单的编写测试的方法就是继承AndroidTestCase写一个自己的TestCase。然后为自己的一组TestCase写一个Activity界面,由界面控制 TestCase的启动,运行和结果报告。但是,你很快会发现,为何要给测试写一个界面呢?这太诡异了。这时就需要一种技术,它可以利用命令行(Shell)来启动一组测试,并且通过命令行的形式给出结果。这就是所谓的Instrumentation。

wordend 相关阅读:

MOTODEV初体验,高效Android开发工具
详解如何实现一个基本的Android用户界面
Android应用开发实战:GPS与加速度传感器
  什么是Instrumentation?

  一般在开发Android程序的时候,需要写一个manifest文件,其结构是:



Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/

<application android:icon="@drawable/icon" android:label="@string/app_name"><activity android:name=".TestApp" android:label="@string/app_name">
……
</activity></application>   

  这样,在启动程序的时候就会先启动一个Application,然后在此Application运行过程中根据情况加载相应的Activity,而Activity是需要一个界面的。但是Instrumentation并不是这样的。你可以将Instrumentation理解为一种没有图形界面的,具有启动能力的,用于监控其他类(用Target Package声明)的工具类。任何想成为Instrumentation的类必须继承android.app.Instrumentation。下面是这个类的解释:

  “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 the application. An Instrumentation implementation is described to the system through an AndroidManifest.xml's tag.“

  对于单元测试,我们需要认真了解的就是android.test.InstrumentationTestRunner类。这是Android单元测试的主入口。它相当于JUnit当中TestRunner的作用。

  那么如何加载它呢,首先要在manifest文件中加入一行关于Instrumentation的声明。比如Android Api Demos中的测试里的manifest是这么写的(我滤掉了所有的注释):



Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/

<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.android.apis.tests"><application><uses-library android:name="android.test.runner"></uses-library></application><instrumentation android:name="android.test.InstrumentationTestRunner" android:targetpackage="com.example.android.apis" android:label="Tests for Api Demos."></instrumentation></manifest>

  如果用Eclipse的ADT插件(0.8版本以上),也可以用图形界面来添加,如下图:


  编辑好 manifest,就可以打包(build,可以用Eclipse ADT来做,也可以用aapt命令手工完成),然后安装到虚拟机上(用adb install命令)。之后就可以利用命令行的方式来加载你的单元测试了。在Android Shell中加载一个Instrumentation的方法是利用以下命令:

  adb shell am instrument –w XXXXXX

  其中-w是指定Instrumentation类的参数标志。一个简单的例子是:

  adb shell am instrument -w com.android.foo/android.test.InstrumentationTestRunner

  当然,也可以利用adb shell先进入android命令行模式,再直接写am instrument –w XXXXXXX。下面将具体介绍如何将根据需要加载一组单元测试。

wordend 相关阅读:

MOTODEV初体验,高效Android开发工具
详解如何实现一个基本的Android用户界面
Android应用开发实战:GPS与加速度传感器
  如何在Android中利用Instrumentation来进行测试?

  在介绍具体的命令之前,我们先理解一下单元测试的层次。一组单元测试可以被组织成若干个TestSuite。每个TestSuite包含若干 TestCase(某个继承android.jar的junit.framework.TestCase的类)。每个TestCase又包含若干个 Test(具体的test方法)。

  如果假设com.android.foo是你的测试代码的包的根。当执行以下命令时,会执行所有的TestCase的所有Test。测试的对象就是在Target Package中指定的包中的代码:

  adb shell am instrument -w com.android.foo/android.test.InstrumentationTestRunner

  如果你想运行一个TestSuite,首先继承android.jar的junit.framework.TestSuite类,实现一个 TestSuite(比如叫com.android.foo.MyTestSuite),然后执行以下命令执行此TestSuite

  adb shell am instrument -e class com.android.foo.MyTestSuite -w com.android.foo/android.test.InstrumentationTestRunner

  其中的-e表示额外的参数,语法为-e [arg1] [value1] [arg2] [value2] …这里用到了class参数。

  如果仅仅想运行一个TestCase(比如叫com.android.foo.MyTestCase),则用以下命令:

  adb shell am instrument -e class com.android.foo.MyTestCase -w com.android.foo/android.test.InstrumentationTestRunner

  如果仅仅想运行一个Test(比如就是上面MyTestCase的testFoo方法),很类似的,就这样写:

  adb shell am instrument -e class com.android.foo.MyTestCase#testFoo -w com.android.foo/android.test.InstrumentationTestRunner

  然后,所有的测试结果会输出到控制台,并会做一系列统计,如标记为E的是Error,标记为F的是Failure,Success的测试则会标记为一个点。这和JUnit的语义一致。如果希望断点调试你的测试,只需要直接在代码上加上断点,然后将运行命令参数的-e后边附加上debug true后运行即可。更加详细的内容可以看InstrumentationTestRunner的Javadoc。我希望Android能尽快有正式的文档来介绍这个内容。

  如何在Android的单元测试中做标记?

  在 android.test.annotation包里定义了几个annotation,包括 @LargeTest,@MediumTest,@SmallTest,@Smoke,和@Suppress。你可以根据自己的需要用这些 annotation来对自己的测试分类。在执行单元测试命令时,可以在-e参数后设置“size large”/ “size medium”/ “size small”来执行具有相应标记的测试。特别的@Supperss可以取消被标记的Test的执行。

  完整的操作过程

  总结以上所有的内容,编写并运行完整的测试需要以下的步骤:




  以上步骤中,在 Android自带的例子中,我发现它有两个manifest.xml。也就是说在步骤3中源代码和测试代码分别生成了两个不同的包。然后步骤4利用 adb install命令安装到了虚拟机上。由于我没有找到Eclipse ADT有办法可以为一个只有Instrumentation,没有Activity的Application打包并安装,于是采用了略微不同的办法完成了这个工作。下文中将一一详细介绍整个过程。

wordend 相关阅读:

MOTODEV初体验,高效Android开发工具
详解如何实现一个基本的Android用户界面
Android应用开发实战:GPS与加速度传感器
  1、编写程序

  我新建了一个项目TestApp,参数为:

  Package Name: com.android.testapp

  Activity Name: MainActivity

  Application Name: TestApp

  以下是MainActivity的源代码:

  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 - a;

  }

  }

  其中,我故意将减法的a – b写成了b – a。

wordend 相关阅读:

MOTODEV初体验,高效Android开发工具
详解如何实现一个基本的Android用户界面
Android应用开发实战:GPS与加速度传感器
  2、编写测试程序

  然后,我新建了一个Source Folder,名为test,并在里面新建了包com.android.testapp.test。并定义了一个TestCase,名为TestMainActivity,源代码如下:

  package com.android.testapp.test;

  import com.android.testapp.MainActivity;

  import android.test.ActivityInstrumentationTestCase;

  import android.test.suitebuilder.annotation.MediumTest;

  public class TestMainActivity extends ActivityInstrumentationTestCase {

  public TestMainActivity() {

  super("com.android.testapp", MainActivity.class);

  }

  public TestMainActivity(String pkg, Class activityClass) {

  super(pkg, activityClass);

  }

  @MediumTest

  public void testSum() {

  assertEquals(3, getActivity().sum(1, 2));

  }

  @MediumTest

  public void testSubstract() {

  assertEquals(-1, getActivity().substract(1, 2));

  }

  }

  我继承了ActivityInstrumentationTestCase。这个TestCase在执行时会自动帮我启动相应的Activity。

  接下来就是程序的Manifest:



Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/

<?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"></action><category android:name="android.intent.category.LAUNCHER"></category></intent-filter></activity><uses-library android:name="android.test.runner"></uses-library></application><instrumentation android:targetpackage="com.android.testapp" android:name="android.test.InstrumentationTestRunner" android:label="Test Unit Tests"></instrumentation></manifest>

  在这个文件中,我将 Activity和Instrumentation的声明写到了一起,而没有像Apis Demo那样分开。请注意里面的标签。如果没有那句,在运行测试时会报告找不到TestRunner。这是由于 Android在build的时候只把需要的东西打包,所以你必须明确的告诉Android Builder这一点。

wordend 相关阅读:

MOTODEV初体验,高效Android开发工具
详解如何实现一个基本的Android用户界面
Android应用开发实战:GPS与加速度传感器
  3、Build和Install

  在 Eclipse上,这两个步骤是一起完成的。只要点一下Run即可。只不过如果你不在Run Configuration里将安装后的Launch Action设为“Do Nothing”,就会自动运行一下你的MainActivity。对于我们,设为Do Nothing即可。如下图:


  完成后,利用命令:

  adb shell pm list packages

  可以在已经安装的pkg列表里看到com.android.testapp。

  4、运行测试,查看结果

  之后就打开命令行,运行以下命令

  adb shell am instrument –e class com.android.testapp.test.TestMainActivity –w com.android.testapp/android.test.InstrumentationTestRunner

  即可看到如下的结果:


  可以看到,单元测试正确的找到了减法中的错误。结果中的成功的测试显示为”.”,一个失败的显示为”F”。只不过我还是不太理解为什么我只写了两个测试方法,Tests run却显示了3。

分享到:
评论

相关推荐

    android Junit单元测试

    在本文中,我们将学习如何在 Eclipse 中创建 Android JUnit 的单元测试工程,并在不同的条件下创建及运行自动测试用例。同时,我们还将学习如何测试 Android 中的 Activity 并识别程序中的错误。 首先,让我们来...

    Android Studio JUnit单元测试

    ### Android Studio JUnit单元测试详解 #### 一、单元测试的重要性及作用 单元测试是软件开发过程中不可或缺的一部分,尤其在Android应用开发中更是如此。它主要用于验证程序中的最小可测试单元——通常是函数或...

    android-junit单元测试(附代码)

    要进行Android的JUnit单元测试,我们需要创建一个测试类,该类继承自`AndroidJUnit4`类,这使得我们可以使用JUnit4的特性。例如: ```java import org.junit.runner.RunWith; import android.support.test.runner....

    android-junit5,使用junit 5进行android测试。.zip

    在Android领域,JUnit作为一款流行的单元测试框架,已经从JUnit4进化到了JUnit5,为开发者提供了更加强大和灵活的测试能力。本文将深入探讨如何在Android环境中利用JUnit5进行测试,并结合开源项目“android-junit5...

    Android JUnit单元测试实例

    这篇内容将深入探讨Android JUnit单元测试的基本实例,帮助开发者理解如何有效地利用它来验证应用程序的功能。 首先,我们需要了解Android JUnit的基本结构。一个简单的Android JUnit测试类通常会继承自`androidx....

    android studio junit测试 demo

    JUnit是一个流行的单元测试框架,广泛用于Java和Android应用的测试。在这个“android studio junit测试 demo”中,我们将探讨如何在Android Studio中设置和执行JUnit测试,特别是针对Activity的测试。 首先,理解...

    android-junit5:使用Android的JUnit 5进行测试

    该插件为项目的每个构建变体配置单元测试任务,以在JUnit Platform上运行。 此外,它附加到android.testOptions为这些测试提供了其他配置选项。 有关如何编写JUnit 5测试的说明,请参见其。 此外,此存储库提供了...

    android 结合Junit进行测试.

    在Android开发中,单元测试是确保代码质量、稳定性和可维护性的重要环节。Junit作为Java领域最流行的单元测试框架,自然也被广泛应用于Android开发。本文将深入探讨如何在Android项目中结合Junit进行测试,以及相关...

    android之Junit ActivityUnitTestCase 演示

    在`TestApp`中,我们可以使用`@RunWith(AndroidJUnit4.class)`注解,结合`@Test`注解的测试方法,以类的形式组织多个测试用例。 总的来说,`JUnit`和`ActivityUnitTestCase`的结合使用,使得我们能够有效地对...

    android junit 单元测测

    ### Android JUnit单元测试详解 在软件开发领域,单元测试是一种不可或缺的质量保证手段,它通过自动化的方式检测代码的各个组成部分是否能够独立正确地运行。对于Android应用开发而言,单元测试同样扮演着至关重要...

    Android单元测试的小例子

    7. **Robolectric**:对于那些需要在没有实际Android环境的情况下运行的单元测试,Robolectric是一个很好的选择。它模拟了Android系统的大部分功能,使测试可以在Java虚拟机上运行。 8. **Testing Best Practices**...

    android-junit-report

    在Android开发中,测试是不可或缺的一环,而JUnit作为Java领域广泛使用的单元测试框架,也在Android平台上得到了应用。"android-junit-report"项目便是针对Android环境优化的JUnit测试报告生成工具,旨在帮助开发者...

    在Android上实现Junit单元测试的四部曲

    ### 在Android上实现JUnit单元测试的四部曲 #### 第一步:创建测试类(继承`AndroidTestCase`) 在Android平台上进行JUnit单元测试时,首先需要创建一个测试类,该类必须继承自`AndroidTestCase`。这是为了确保...

    Android下使用JUnitTest用例

    然后,在这个目录下创建一个新的Java类,继承自`androidx.test.ext.junit.runners.AndroidJUnit4`。这样,你的测试类就可以使用JUnit4的注解了。 4. **编写测试用例** 使用JUnit的`@Test`注解标记测试方法,这些...

    junit单元测试框架

    在“22_android下junit测试框架配置.avi”这个视频文件中,很可能是详细讲解了如何在Android项目中配置和使用JUnit进行单元测试,包括添加依赖、创建测试类、编写测试方法,以及如何运行和查看测试结果。观看这个...

    android-junit-report-1.5.8.zip官网下的

    总结来说,Android JUnit Report 1.5.8是一个轻量级的工具,旨在简化Android项目的单元测试报告生成过程。通过有效的集成和定制,开发者可以充分利用这个库提升测试效率,保证代码质量,从而为项目提供更加可靠的...

    教你在Android Studio 中进行单元测试(源码)

    2. `@RunWith(AndroidJUnit4.class)`注解表明测试类使用AndroidJUnit4运行器。 六、Mockito的使用 1. 配置Mockito:在`build.gradle`文件中添加Mockito依赖,然后在测试类中使用`@RunWith(MockitoJUnitRunner....

    用Junit对Android应用进行单元测试

    在Android应用开发中,单元测试是一项至关重要的任务,它能够帮助开发者确保代码的质量,发现潜在的bug,并在修改代码后快速验证其正确性。本文主要介绍如何使用JUnit框架对Android应用进行单元测试,以SimpleCalc这...

    Android-节省时间并在Android上清除您的单元测试

    在测试类中,通常会继承`AndroidJUnit4`或者`InstrumentationTestCase`,这取决于你是否需要访问Android系统服务或运行在模拟器/真实设备上。 在编写测试用例时,遵循单一测试原则是非常重要的,每个测试方法应该只...

Global site tag (gtag.js) - Google Analytics