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

Android Junit使用

阅读更多

AndroidJUnit(一)JUnit初步解析

Android SDK 1.5已经将JUnit包含进来了,但是一直没有去深入了解,以前在使用一些C++的开源库中学习过与CPPUnit,简要分析过其主要框架,如下:

这次在学习Android SDK 1.6中的例子程序APIDemoes中的过程中,看到了一个test文件夹,似乎就是使用了JUnit,于是就开始学习Android中如何使用JUnitAPIDemoes\test文件夹下的测试代码相对比较复杂,我们会循序渐进的学习,逐步深入的理解,在后面为大家详细解析如何阅读这些测试代码,本篇幅就初步解析JUnit

什么是 JUnit

JUnit是采用测试驱动开发的方式,也就是说在开发前先写好测试代码,主要用来说明被测试的代码会被如何使用,错误处理等;然后开始写代码,并在测试代码中逐步测试这些代码,直到最后在测试代码中完全通过。

现简要说JUnit4大功能

1.                  管理测试用例。修改了哪些代码,这些代码的修改会对哪些部分有影响,通过JUnit将这次的修改做个完整测试。这也就JUnit中所谓的TestSuite

2.                  定义测试代码。这也就是JUnit中所谓的TestCase,根据源代码的测试需要定义每个TestCase,并将TestCase添加到相应的TestSuite方便管理。

3.                  定义测试环境。在TestCase测试前会先调用环境配置,在测试中使用,当然也可以在测试用例中直接定义测试环境。

4.                  检测测试结果。对于每种正常、异常情况下的测试,运行结果是什么、结果是否是我们预期的等都需要有个明确的定义,JUnit在这方面提供了强大的功能。

以上部分与我们平常使用IDE调试的过程是完全一样的,只不过是增加了测试用例管理、测试结果检测等功能,提高了单元的效率,保证了单元测试的完整性,明确了单元测试的目标。

以上4大功能,在JUnit的框架中是如何实现的了,在下一篇幅JUnit例子分析中,通过一个简要的例子,详细说明4大功能是如何实现的。

 

 

AndroidJUnit(二)JUnit例子分析

1.                              管理测试用例;

2.                              定义测试代码;

3.                              定义测试环境;

4.                              检测测试结果;

结合主要功能,举个简单的例子分析如下:

源代码:
public class SampleCalculator
{
public int add(int augend , int addend)
{return augend + addend ;}

public int subtration(int minuend , int subtrahend)

{ return minuend – subtrahend ;}

}

测试用例(TestCase):
import junit.framework.TestCase;
public class TestSample extends TestCase
{
private int a;
private int b;
private int r1,r2;
void setUp() /*
开始测试当前用例初始化测试环境*/
{
a = 50;
b = 20;
r1 = 70;
r2 = 30;
}

void tearDown()/*当期用例测试结束*/
{}

public void testAdd()/*测试SampleCalculator 类的Add函数*/
{
SampleCalculator calculator = new SampleCalculator();
int result = calculator.add(a , b);
assertEquals(r1 , result);/*
检测测试结果*/
}

public void testSubtration()/*测试SampleCalculator 类的Subtration函数*/
{
SampleCalculator calculator = new SampleCalculator();
int result = calculator.subtration(a , b);
assertEquals(r2 , result);/*
检测测试结果*/
}
}
以上TestSample测试用例中就对SampleCalculator进行了完整的单元测试,并对测试结果做了预期说明。

TestCase的管理
import junit.framework.Test;
import junit.framework.TestSuite;
public class TestAll
{
public static Test suite()
{
TestSuite suite = new TestSuite(“TestSuite Test”);
suite.addTestSuite(TestSample.class);
return suite;
}
}

以上就将TestSample增加到“TestSuite Test”中,将来在选择测试用例的过程中只要选择了TestSuite TestTestSample就将加入当前测试中。如果将来SampleCalculator增加了其他功能,只需要在TestSample增加相应的测试代码。

最后需要说明的:对TestCase的管理,是完全界面化的,JUnit会自动产生UI界面,运行以上测试的例子,JUnit的界面如下:

可能还需要下载JUint packeage,最后送给大家一句话:大胆尝试下,你会发现编程真的可以如此美好

 

 

 

AndroidJUnit(三)JUnit深入解析(上)

通过前面2篇文章的学习,我们对JUnit有了初步的认识,下面我们将深入的解析JUnit数据包。整个JUnit的数据包应该是很强大的,但是一般来说,不一定每个工程都需要这些数据包,而是在JUnit部分数据包的基础上扩展出自己的数据包,Android SDK中也不例外。至于JUnit完整的包,这里我们就不详细分析了,我们这里只解析Android SDK中包含的那些JUnit数据包,以及Android SDKJUnit的基础上扩展的一些数据包,如下:

SDK

功能说明

junit.framework

JUnit测试框架

junit.runner

实用工具类支持JUnit测试框架

android.test

Android JUnit测试框架的扩展包

android.test.mock

Android的一些辅助类

android.test.suitebuilder

实用工具类,支持类的测试运行

在这些包中最为重要的是:junit.frameworkandroid.test,其中前者是JUnit的核心包,后者是Andoid SDKJunit.framework的基础上扩展出来的包,我们将重点解析这2个包。

首先解析junit.framework包,结构如下:

通过这张图,大家就可以比较清晰的看到JUnit的主要框架,再回去看下上篇文章的例子,对前面的例子感觉明白多了。做个简要的总结,如下:

1.                              TestSuitTestSuite是测试用例的集合;

2.                              TestCase:定义运行多个测试用例;

3.                              TestResult:收集一个测试案例的结果,测试结果分为失败和错误,如果未能预计的断言就是失

4.                              败,错误就像一个ArrayIndexOutOfBoundsException异常而导致的无法预料的问题;

5.                              TestFailure:测试失败时捕获的异常;

6.                              Assert:断言的方法集,当断言失败时显示信息;

TestCaseTestSuite之间的关系,有些类似于图元对象与容器对象之间的关系,在面向对象的语言C++JAVA中较常见,在这里就不多说了。

举个简单的例子,并简要说明过程

第一步:实现TestCase

1.                              继承父类TestCase

2.                              定义一下变量在测试中使用;

3.                              setUp()中初始化这些变量;

4.                              tearDown()中清理这些变量;
public class MathTest extends TestCase{
protected double fValue1;
protected double fValue2;
protected void setUp(){
fValue1= 2.0;
fValue2= 3.0;
}
}

5.                              编写测试单元代码;
public void testAdd() {
double result= fValue1 + fValue2;
assertTrue(result == 5.0);
}

6.                              运行测试用例,这里有2种方法可以使用:

·                                 静态类型:覆盖runTes()和定义测试函数。最常用的就是采用java的匿名类,如下:
TestCase test= new MathTest(“add”){
public void runTest() { testAdd();}
};
test.run();

·                                 动态类型:使用反射来实现runTest,它动态地发现并调用的方法,在这种情况下,测试案例的名字对应的测试方法来运行,如下:TestCase= new MathTest(“testAdd”);
test.run();

相比之下,第2种更符合面向对象的思维。

第二步:将TestCase添加到TestSuilt

           TestSuite suite= new TestSuite();

           suite.addTest(new MathTest("testAdd"));

由于TestSuite可以自动从TestCase中提取测试单元并运行,也可以用如下方法:

           TestSuite suite= new TestSuite(MathTest.class);

一个测试用例就完成了,想要更加详细的了解junit.framework,还是到Android SDK中仔细阅读。

 

 

 

AndroidJUnit(四)AndroidTestRunner

随着学习的深入,发现包在前面的篇幅中,我们忽略了android.test包中一个重要的类AndroidTestRunner,这个类是android.test包的核心类,下面为大家详细说明,并补充说明一些相关的内容。

junit.framework包中的TestListener接口

这个接口的函数,列举如下:

与这个接口,相关的类就只用TestResult,相关接口如下:

看到这里就应该知道如何使用了,具体的使用在下一篇幅例子中说明。

junit.runner包,结构如下:

这是一个对junit.framework的辅助包,包主要就是BaseTestRunner类,其实现了TestListener接口,主要功能是:对测试过程中ErrorFailure的检查。
有了这些补充说明,下面学习android.test包中一个重要的类AndroidTestRunner

AndroidTestRunner类结构,如下图所示:

其主要接口函数,列举如下:

看到setContext(Context context)这个函数的这个参数Context context,总算让我看到junitAndroid的结合点了,在看下其他几个函数,我们会发现,这个类是android.test的核心控制类,大家心中的疑惑顿时就没有了。列举一个简要的例子,如下:
AndroidTestRunner testRunner = new AndroidTestRunner();
testRunner.setTest( new ExampleSuite() );
testRunner.addTestListener( this );
testRunner.setContext( parentActivity );
testRunner.runTest();
通过AndroidTestRunner控制整个测试,并与我们的Activity向结合,具体的使用在下一篇幅中详细说明。

 

 

AndroidJUnit(五)AndroidTest例子分析

前面我们学习了android.test包中的大部分类,是该通过学习具体的例子将前面的知识融会贯通,让我们的理解更加深刻,例子程序代码下载地址,下载后添加Eclipes的工程中,边看这篇文章边阅读例子程序的代码。

首先分析整个工程的结构图,如下:

AndroidTestCaseTestsuite前面的篇幅中已经学习过了,ContestTestMathTestSomeTestExampleSuite在前面的例子中已经为大家介绍了,这里我们主要说明整个程序是如何运行的?

核心类代码简要列举,如下:

public class JUnit extends Activity {
static final String LOG_TAG = “junit”;
Thread testRunnerThread = null;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Button launcherButton = (Button)findViewById( R.id.launch_button );
launcherButton.setOnClickListener( new View.OnClickListener() {
public void onClick( View view ) {startTest();}
} );
}
private synchronized void startTest()
{
if( ( testRunnerThread != null ) &&!testRunnerThread.isAlive() )
testRunnerThread = null;
if( testRunnerThread == null )
{
testRunnerThread = new Thread( new TestRunner( this ) );
testRunnerThread.start();
}
else
{
Toast.makeText(this, “Test is still running”, Toast.LENGTH_SHORT).show();
}

class TestRunner implements Runnable,TestListener
{
static final String LOG_TAG = “TestRunner”;
int testCounter;
int errorCounter;
int failureCounter;
……;
Activity parentActivity;

public TestRunner( Activity parentActivity )
{this.parentActivity = parentActivity;}

public void run()
{
testCounter = 0;
errorCounter = 0;
failureCounter = 0;
………….;

Log.d( LOG_TAG, “Test started” );
/*
整个代码的核心*/
AndroidTestRunner testRunner = new AndroidTestRunner();
testRunner.setTest( new ExampleSuite() );
testRunner.addTestListener( this );
testRunner.setContext( parentActivity );
testRunner.runTest();
Log.d( LOG_TAG, “Test ended” );
}

// TestListener
public void addError(Test test, Throwable t)
{
Log.d( LOG_TAG, “addError: “+test.getClass().getName() );
Log.d( LOG_TAG, t.getMessage(), t );
++errorCounter;
…….;
}

public void addFailure(Test test, AssertionFailedError t)
{
Log.d( LOG_TAG, “addFailure: “+test.getClass().getName() );
Log.d( LOG_TAG, t.getMessage(), t );
++failureCounter;
…….;
}

public void endTest(Test test)
{
Log.d( LOG_TAG, “endTest: “+test.getClass().getName() );
…..;
}

public void startTest(Test test)
{
Log.d( LOG_TAG, “startTest: “+test.getClass().getName() );
++testCounter;
…….;
}

}
通过将源工程中的代码简单整理后,就可以看到TestRunner这个工作者线程(window中的术语,没有界面的线程)的作用,这让我们对TestListener有了更加深入的了解。

整个程序的核心代码,如下:

public void run()
{
……;
/*
整个代码的核心*/
AndroidTestRunner testRunner = new AndroidTestRunner();
testRunner.setTest( new ExampleSuite() );
testRunner.addTestListener( this );
testRunner.setContext( parentActivity );
testRunner.runTest();
…….;
}

AndroidTestRunner这个核心类,在前面的篇幅中我们已经学习过,再次回忆下这张图(在大脑中留下深刻的记忆,后面会经常使用):

红色划线部分代表例子程序代码中使用的AndroidTestRunner类的函数。这里使用单独线程的主要作用就是:testRunner.runTest();会占用大量的时间,如果直接在UI线程中运行会阻滞UI线程,导致界面停止反应,这对用户的操作会有很大的影响。

如何将TestRunner 中的测试信息显示在界面上?

在前面的Snake例子程序中介绍过:Android SDK为我们提供了Handler,通过Handler与一个线程的消息队列相关联,发送和处理信息。在这个例子中使用了Activity类的runOnUiThread (Runnable action)函数,这个函数的主要功能:在UI线程中运行指定的操作,如果当前线程是UI线程,然后采取行动立即执行;如果当前线程不是UI线程,发送消息到UI线程的事件队列。

整个程序就介绍完了,运行程序后的界面如下:

在这里需要特殊说明的是:打开AndroidManifest.xml文件,发现<application>有个以前没有见过的标记,如下:
<application android:label=”@string/app_name”>
<uses-library android:name=”android.test.runner”/>
<activity android:name=”.JUnit” android:label=”@string/app_name”>
<intent-filter>
<action android:name=”android.intent.action.MAIN” />
<category android:name=”android.intent.category.LAUNCHER” />
</intent-filter>
</activity>
</application>
user-library
元素说明:指定一个共享库,应用程序需要连接的。默认情况下会连接所有的Android库,然而一些软件包(如地图和AWT)是不会自动连接独立的库,以确定哪些库需要包含这些特定的包代码文件。

总结说明

这个例子已经学习完了,虽然它比较简单,但是让我们清晰的了解如何使用AndroidTestRunner,后面我们将继续介绍一些复杂的例子,更加深入的学习。

 

 

 

AndroidJUnit(六)如何运行单元测试?

前面我们学习了很多JUnit的程序,在Android ADT插件中已经为我们提供了很多这方面的功能,方便我们进行单元测试。但是如何进行单元测试,例如在ApiDemos\test提供的测试例子程序如何运行,对于我们这些初学者来说有些茫然,我也是在网上查找了不少这方面的的资料学习,才知道如何运行测试单元,因此在这里总结说明与大家分享。总结起来,大概有4种不同的方法:

使用ADT 运行测试单元

Eclipes中选择工程,单击右键,在Run as/Debug as子菜单选项中选择Android JUnit Test,如下:

单击运行后,应用程序将启动,在Eclipes中会出现个新的面板JUnit,如下:

这个界面上就显示了测试的结果,这种方法操作比较简单,但是要想自己写单元测试就的必须深入的去了解后面2中运行的方法。

通过AVD 运行测试单元

运行AVD,选择Dev Tool ,当前界面如下:

双击Instrumentation后,界面如下:

测试例子开始运行,在LogCat中查看运行过程输出的信息,界面如下:

这些信息就是测试例子输出的信息。

通过adb shell 命令运行测试单元

这种方法应该是为linux程序员设置的,完全的命令行,使用起来相对比较麻烦,命令格式如下:

按照上面的命令行格式,输入:adb shell am instrument -w com.xmobileapp.hello/android.test.Instrumentatio

分享到:
评论
1 楼 luochuang 2013-03-04  
你粘過來的東西,起碼自己測試過在貼上來。

相关推荐

Global site tag (gtag.js) - Google Analytics