Android单元测试,使用ThreadingTest进行全新体验

1、 背景

长期以来,软件测试工程师都在如何提高软件系统质量和如何提高测试效率的道路上艰难地探索,但始终没有一款性能全面的测试工具可以满足需求。

ThreadingTest智能型测试工具系列一期,是基于程序源代码的白盒测试工具。采取前端分析器和后端结果分析分离的技术路线,实现对多种语言的编译器级分析和多维度测试。

ThreadingTest通过一系列自动、高效、可视化技术,使软件维护与开发效率加倍、成本减半、系统软件质量提高几个数量级。

ThreadingTest采用离线分析操作,即使电脑脱离互联网也可以获得同样的体验,保障代码的安全。

2、 ThreadingTestAndroid JUnit Test单元测试

ThreadingTest AndroidJUnit Test是基于Android JUnit Test,利用ThreadingTest本身的优势,编写的一套单元测试组件。在原有的Android JUnit Test测试驱动代码的基础上,只需要进行很小的改动,就可以修改为符合ThreadingTest Android JUnit Test测试代码的单元测试。除此之外,两者的测试几乎没有差别,只需要您在测试时,打开TT实时监控来接收数据,而在测试过程中,则无需其他操作,甚至感觉不到数据的收集过程。

对于传统的单元测试,在单元测试结束后,测试人员只能获得测试结果是否符合预期结果。如果与预期结果存在差异,也无法立即得到错误原因。

当使用ThreadingTest AndroidJUnit Test进行单元测试时,还是相同的测试体验,却能够得到白盒测试的数据,当单元执行结束后,可以根据产生的数据来分析程序的出错点,使Bug的查找更快速,更准确,而为此付出最小的代价。

3、 Android单元测试的编写

Android单元测试有两种方法,首先作为java程序,可以试用JUnit Test进行测试,另外也可使用Android JUnit Test进行单元测试。

1)、JUnit Test进行单元测试

JUnit对Android应用程序进行单元测试需要使用Java命令来启动或者在eclipse里面将启动的Bootstrap Entries改为JRE,但是这种只能测试逻辑代码,因为是是运行在JVM上,而不是Android系统中,所以不能测试Android有关的代码。

使用JUnit测试的代码,需要在函数的之前加@Test,函数必须为public类型,在eclipse中,在类上右击,选择JUnit Test即可进行测试。

2)Android JUnit Test进行单元测试

Android JUnit Test单元测试是一组直接或间接继承自junit.framework.Testcase的类集合,入口是InstrumentationTestRunner。

使用Android JUnit Test测试,也存在两种测试方法,测试驱动与测试代码在同一工程下和测试驱动和测试代码位于不同工程,两者之间并无巨大差异,只是在测试时,前者只安装一个App,后者安装两个App。

如下为一个单元测试的实例:

步骤 1:准备好需要测试的源代码

步骤2:添加测试类,编写测试代码


package  calculator.xwg.test;

import  java.util.ArrayList;

import java.util.LinkedList;

import  android.test.ActivityInstrumentationTestCase2;

import  android.app.AlertDialog;

import  android.app.Instrumentation;

import  android.widget.Button;

import  android.widget.ListView;

import  android.widget.TextView;

import calculator.xwg.CalculatorMainActivity;

publicclass  CalculatorMainActivityTestextends

ActivityInstrumentationTestCase2<CalculatorMainActivity>  {

private  InstrumentationmInstrumentation;

private  CalculatorMainActivitymActivity;

private TextViewmQuestionText;

private TextViewmAnswerText;

private ButtonmCalculateButton;

private ButtonmButton1;

private ButtonmButtonPlus;

private ButtonmButtonAngle;

private ButtonmButtonDegree;

private ButtonmButtonF6;

class AssertPair{

public AssertPair(CharSequence  quest, CharSequence res){

question = quest;

result = res;

}

boolean  assertResult(){

return (question.toString().compareTo(result.toString())  == 0);

}

public CharSequence question;

public CharSequence result;

}

ArrayList<AssertPair>  assertList = new  ArrayList<AssertPair>();

AssertPair  mAssertPair;

FailureInfo  mFailureInfo;

@SuppressWarnings("deprecation")

public  CalculatorMainActivityTest() {

super("calculator.xwg",  CalculatorMainActivity.class);

//TODO  Auto-generated constructor stub

}

@Override

protectedvoid setUp()throws Exception {

super.setUp();

mInstrumentation =  getInstrumentation();

setActivityInitialTouchMode(false);

mActivity =  (CalculatorMainActivity) getActivity();

mQuestionText = (TextView)mActivity.findViewById(calculator.xwg.R.id.textQuestion);

mAnswerText = (TextView)mActivity.findViewById(calculator.xwg.R.id.textAnswer);

mCalculateButton = (Button)mActivity.findViewById(calculator.xwg.R.id.button74);

mButton1 = (Button)mActivity.findViewById(calculator.xwg.R.id.button60);

mButtonPlus = (Button)mActivity.findViewById(calculator.xwg.R.id.button63);

mButtonAngle = (Button)mActivity.findViewById(calculator.xwg.R.id.button03);

mButtonDegree = (Button)mActivity.findViewById(calculator.xwg.R.id.button02);

mButtonF6 = (Button)mActivity.findViewById(calculator.xwg.R.id.buttonF6);

mActivity.engine.clearCustomFunctions();

}  // end of  setUp() method definition

@Override

protectedvoid tearDown()throws Exception {

mActivity.engine.clearCustomFunctions();

super.tearDown();

}

publicvoid  testPreConditions() {

//assertTrue(mSpinner.getOnItemSelectedListener()  != null);

//assertTrue(mPlanetData != null);

//assertEquals(mPlanetData.getCount(),ADAPTER_COUNT);

}  // end of  testPreConditions() method definition

publicvoid  testCalculate() {

LinkedList<AssertPair>  checkItemList =new LinkedList<AssertPair>();

checkItemList.add(new AssertPair("1-2×((3+4)/58+8)×25%","-3.06034482759"));

checkItemList.add(new AssertPair("root(16,4)","2"));

checkItemList.add(new AssertPair("sin(0°)","0"));

checkItemList.add(new AssertPair("sin(30°)","0.5"));

checkItemList.add(new AssertPair("sin(390°)","0.5"));

checkItemList.add(new AssertPair("sin(-330°)","0.5"));

checkItemList.add(new AssertPair("sin(90°)","1"));

checkItemList.add(new AssertPair("sin(145°)","0.573576436351"));

checkItemList.add(new AssertPair("sin(180°)","0"));

checkItemList.add(new AssertPair("sin(200°)","-0.342020143326"));

checkItemList.add(new AssertPair("sin(270°)","-1"));

checkItemList.add(new AssertPair("sin(300°)","-0.866025403784"));

checkItemList.add(new AssertPair("sin(360°)","0"));

checkItemList.add(new AssertPair("sin(π/6)","0.5"));

checkItemList.add(new AssertPair("tan(0)","0"));

checkItemList.add(new AssertPair("tan(0.2)","0.202710035509"));

checkItemList.add(new AssertPair("tan(0.4)","0.422793218738"));

checkItemList.add(new AssertPair("tan(0.6)","0.684136808342"));

checkItemList.add(new AssertPair("tan(0.8)","1.02963855705"));

checkItemList.add(new AssertPair("tan(1.0)","1.55740772465"));

checkItemList.add(new AssertPair("tan(1.2)","2.57215162213"));

checkItemList.add(new AssertPair("tan(1.4)","5.79788371548"));

checkItemList.add(new AssertPair("tan(1.8)","-4.28626167463"));

checkItemList.add(new AssertPair("tan(2.0)","-2.18503986326"));

checkItemList.add(new AssertPair("tan(2.2)","-1.37382305677"));

checkItemList.add(new AssertPair("tan(2.4)","-0.916014289673"));

checkItemList.add(new AssertPair("tan(2.6)","-0.60159661309"));

checkItemList.add(new AssertPair("tan(2.8)","-0.355529831651"));

checkItemList.add(new AssertPair("tan(3.0)","-0.142546543074"));

checkItemList.add(new AssertPair("tan(3.2)","0.0584738544596"));

checkItemList.add(new AssertPair("tan(π/2)","tan:Invalid  input."));

checkItemList.add(new AssertPair("tan(π)","0"));

checkItemList.add(new AssertPair("tan(π/2×3)","tan:Invalid  input."));

checkItemList.add(new AssertPair("tan(2×π)","0"));

checkItemList.add(new AssertPair("tan(45°)","1"));

checkItemList.add(new AssertPair("tan(90°)","tan:Invalid  input."));

checkItemList.add(new AssertPair("tan(405°)","1"));

checkItemList.add(new AssertPair("tan(-315°)","1"));

checkItemList.add(new AssertPair("tan(-675°)","1"));

checkItemList.add(new AssertPair("1+1","2"));

checkItemList.add(new AssertPair("(1+2i)×(3-4i)/(5+6i)","1.0983607-0.91803279i"));

for(final AssertPair  pair : checkItemList){

mActivity.runOnUiThread(

new Runnable() {

publicvoid run() {

mQuestionText.setText(pair.question);

mActivity.onButtonClick(mCalculateButton);

}

}

);

mInstrumentation.waitForIdleSync();

assertEquals("The  result of " + pair.question +":", pair.result,mAnswerText.getText());

}

}

publicvoid  testConvert() {

mActivity.runOnUiThread(

new Runnable() {

publicvoid run() {

mQuestionText.setText("1-i");

mActivity.onButtonClick(mButtonAngle);

}

}

);

mInstrumentation.waitForIdleSync();

assertEquals("1.4142136∠5.4977871",mAnswerText.getText());

mActivity.runOnUiThread(

new Runnable() {

publicvoid run() {

mQuestionText.setText("1-i");

mActivity.onButtonClick(mButtonDegree);

}

}

);

mInstrumentation.waitForIdleSync();

assertEquals("1.4142136∠315°",mAnswerText.getText());

}

publicvoid  testContinue() {

mActivity.runOnUiThread(

new Runnable() {

publicvoid run() {

mQuestionText.setText("1-i");

mActivity.onButtonClick(mButtonAngle);

assertList.add(new AssertPair("1.4142136∠5.4977871",mAnswerText.getText()));

mActivity.onButtonClick(mButtonDegree);

assertList.add(new AssertPair("1.4142136∠315°",mAnswerText.getText()));

}

}

);

mInstrumentation.waitForIdleSync();

for(AssertPair  pair :assertList){

assertEquals(pair.question, pair.result);

}

assertList.clear();

}

publicvoid testCustomFunction()  {

mActivity.runOnUiThread(

new Runnable() {

publicvoid run() {

mActivity.onButtonClick(mButtonF6);

mActivity.onButtonClick("5");

mActivity.onButtonClick(")");

mActivity.onButtonClick("=");

mFailureInfo =  FailureInfo.checkFailure("Unknown keyword:F",mAnswerText.getText());

if(mFailureInfo !=null)return;

mQuestionText.setText("π×#1×#1");

mActivity.onButtonClick("FS");

TextView  tv = (TextView)mActivity.mDialog.findViewById(calculator.xwg.R.id.inputText);

tv.setText("Test");

Button  ok = (Button)mActivity.mDialog.findViewById(calculator.xwg.R.id.buttonOK);

ok.performClick();

ListView  lv = (ListView)((AlertDialog)mActivity.mDialog).getListView();

lv.requestFocus();

lv.setSelection(5);

lv.performItemClick(null, 5, 5);

mActivity.onButtonClick(mButtonF6);

mActivity.onButtonClick("5");

mActivity.onButtonClick(")");

mActivity.onButtonClick("=");

mFailureInfo =  FailureInfo.checkFailure("78.5398163397",mAnswerText.getText());

if(mFailureInfo !=null)return;

mActivity.engine.clearCustomFunctions();

}

}

);

mInstrumentation.waitForIdleSync();

if(mFailureInfo !=null){

assertEquals(mFailureInfo.mExpect,mFailureInfo.mResult);

mFailureInfo =null;

}

}

}

步骤3:修改AndroidManifest.xml文件


<?xmlversion="1.0" encoding="utf-8"?>

<manifestxmlns:android="http://schemas.android.com/apk/res/android"

package="calculator.xwg"

android:versionCode="1"

android:versionName="1.0">

<uses-sdkandroid:minSdkVersion="8" />

<uses-permissionandroid:name="android.permission.INTERNET"></uses-permission>

<applicationandroid:label="@string/app_name" android:icon="@drawable/calculator">

<uses-libraryandroid:name="android.test.runner"/>

<activityandroid:name=".CalculatorMainActivity"

android:label="@string/app_name">

<intent-filter>

<actionandroid:name="android.intent.action.MAIN" />

<categoryandroid:name="android.intent.category.LAUNCHER" />

</intent-filter>

</activity>

<activityandroid:name="HelpActivity"></activity>

</application>

<instrumentation

android:name="android.test.InstrumentationTestRunner"

android:targetPackage="calculator.xwg"

android:label="Tests for TT  calculator."/>

</manifest>

注意:绿色背景为添加部分。其中android:label="Testsfor TT calculator."在模拟器中的Dev Tools工具中,设置Instrumentation下显示的名称,在步骤4运行中,点击该标签,也可运行单元测试。在ThreadingTest AndroidJUnit Test中也是重要一步,可以设置多个单元,多个名称,每个名称尽量不要重复,以区分不同的单元测试。

步骤4:运行测试类

运行测试类有三种方式,包括:

1、 命令行方式

使用adb命令启动单元测试

2、 eclipse中选择Android JUnit Test运行方式

在eclipse中,右击测试工程,选择run as -> AndroidJUnit Test

3、 模拟器中,使用Dev Tools

在模拟器中安装该程序后,在Dev Tools工具中,选择Instrumentation下显示的与android:label同名的标签运行单元测试。

4、 ThreadingTest单元测试的编写

要使用ThreadingTest进行单元测试类的编写,需要将所有的测试类写到一个单独的文件夹下,在进行编译工程时,使用参数-filter将其从编译路径中排除,不对其进行插桩。如下图所示:

被测源码放在src文件夹中,单元测试驱动代码放在test_src文件下。

其他方面,需要在Android单元测试上进行的修改为:

1、引入ThreadingTestAndroid jar包,JavaParser-Android.jar和通信包jeromq-0.3.0-SNAPSHOT.jar。

2、将继承AndroidJUnit Test类换成继承ThreadingTest Android JUnit Test类,ThreadingTest Android JUnit Test类中与AndroidJUnit Test相对应的类为在类名前加TT。例如与InstrumentationTestCase相对应的类为TTInstrumentationTestCase,TT AndroidJUnit Test类所在的包为com.zoa.android.test。

3、在重载了setUp和tearDown函数的测试类中,需要分别调用super.setUp()和super.tearDown()函数,否则无法对数据进行惊醒测试用例的区分,如果没无需进行初始化和资源释放则不用继承setUp()和tearDown()函数。

4、其他操作同Android JUnit Test操作相同。

如下为一个与上面Android JUnitTest单元测试类相对应的TT Android JUnit Test单元测试类,添加背景色的为需要注意的点,其他的与原测试代码相同,无需改动:


package  calculator.xwg.test;

import  java.util.ArrayList;

import  java.util.LinkedList;

import  com.zoa.android.test.TTActivityInstrumentationTestCase2;

import  android.app.AlertDialog;

import  android.app.Instrumentation;

import  android.widget.Button;

import  android.widget.ListView;

import  android.widget.TextView;

import  calculator.xwg.CalculatorMainActivity;

publicclass  CalculatorMainActivityTestextends

TTActivityInstrumentationTestCase2<CalculatorMainActivity>  {

…//  与上面相同的代码和描述

@Override

protectedvoid setUp()throws Exception {

super.setUp(); //如重写setUp函数,此句为必须

…//  与上面相同的代码和描述

}  // end of  setUp() method definition

@Override

protectedvoid tearDown()throws Exception {

…//  与上面相同的代码和描述

super.tearDown(); //如重写tearDown函数,此句为必须

}

…//  与上面相同的代码和描述

}

5、 ThreadingTest单元测试的编译

编写完成TT Android JUnitTest 测试类之后,使用TT对工程进行编译。

1、修改编译文件,如果是单一编码格式的工程,需要修改%TT_Path%/ant-build-a/android-instru_en.xml文件,多种编码格式源码的工程,则需要修改%TT_Path%/ant-build-a/android-instru_code_en.xml文件。修改内容为,添加-filter参数,修改方法为:

添加filterpath属性,用于过滤不需要插桩的单元测试驱动类文件。

<propertylocation="不需要插桩编译的路径,这里为test_src路径"name="filterpath"/>

<argline="&quot;${propath}&quot; &quot;${TT}&quot; -tt=&quot;${testpropath}&quot;-encoding=${encoding}-filter=&quot;${filterpath}&quot;-s=&quot;${testpropath}/src&quot;"/>

在运行JavaParser处,添加绿色背景参数。

注:demo版本中需手动修改,后续版本将对此进行改进。

2、打开TT,创建一个新的工程,与非单元测试工程的编译相同。详见:http://www.threadingtest.com/xwiki/bin/view/ZOA%7C4.演示/Android+程序测试配置

6、 ThreadingTest单元测试的运行

在真机中测试时,需要安装Dev Tools工具。模拟器中附带该工具。

将上一步中,TT编译生成的APK文件,安装到模拟器或真机中,安装之后,会在Dev Tools工具下,Instrumentation中会出现与AndroidManifest.xml文件中android:label设置的同名的标签,点击可运行ThreadingTest单元测试。

在运行ThreadingTest单元测试时,需要打开TT接收数据,否则测试会阻塞在消息发送处而无法进行。

模拟器测试步骤为:

1、打开TT,选择将要运行的测试的工程,然后打开实时监控界面,新建一个测试用例。

2、打开模拟器。

3、进行端口重定向

双击运行adb-android.bat,运行的命令为:

adb forward tcp:15555tcp:15555

adb forward tcp:15556tcp:15556

adb forward tcp:15557tcp:15557

adb forward tcp:15558tcp:15558

其中adb需要在环境变量中配置好,如果未配置,也可手动切换到%Android_sdk%\platform-tools目录下手动打开命令行窗口,运行上述命令。

如果运行adb forward –list出现:

其中,emulator-5554也可能是其他名称,则说明配置成功。

4、勾选上测试用例,set Ip为127.0.0.1,确定后点击开始。

5、打开DevTools,点击Instrumentation进入,点击工程中设置的标签名,如Tests for TT calculator.

点击后,开始运行单元测试。

此时TT实时监控界面会有数据的接收:

单元测试运行运行结束后,右击测试用例树右上角的刷新按钮,选择Update Testcase

会增加红色框中的测试用例,首先是与勾选的测试用例同级同名的测试类型,然后依次为测试类所在的包名,类名以及运行测试函数名。

在单元测试开始之前,被测程序的初始化数据会被保存在初始勾选的测试用例中,这里为UnitTest中。单元测试开始之后,产生的测试数据会被保存到,与测试驱动函数对应的测试用例当中。

TT单元测试完成。

真机测试步骤为:

1、打开TT,选择将要运行的测试的工程,然后打开实时监控界面,新建一个测试用例。

2、勾选上测试用例,set Ip为真机的Ip地址,确定后点击开始。

3、同模拟器测试步骤5。

对移动端白盒测试技术或者性能测试感兴趣,请加入群符号执行  339834199

软件试用申请官网:www.threadingtest.com

Android单元测试,使用ThreadingTest进行全新体验

时间: 2024-10-02 03:14:51

Android单元测试,使用ThreadingTest进行全新体验的相关文章

Android测试工具ThreadingTest开放API接口说明

ThreadingTest(简称TT)第一期是一款Android白盒测试工具,使用离线检测的方式,在保护用户源代码的基础上,运用插装.第五代覆盖率等技术,为开发工程师与测试工程师提供一套高效可量化.可视化的交流工具.对比其它测试工具,TT在自动化测试时,会对应测试用例自动生成测试用例和代码之间的关系以及函数覆盖率,并且以TT自带的双向追溯图进行展示,在整个自动化测试进行过程中,TT还会以示波器界面可视化的监控整个自动化测试中每时每刻获取的测试数据. 基于其它测试工具测试时,TT还开放了API接口

android单元测试

http://blog.csdn.net/duancanmeng/article/details/7458851 第一步:在AndroidManifest.xml中加入如下两段代码: 代码一 <uses-library android:name="android.test.runner"/>代表把第三方中的依赖库引入进来 代码二 <instrumentation android:name="android.test.InstrumentationTestRu

android单元测试AndroidTestCase

在实际开发中,开发android软件的过程需要不断的进行测试.而是用Junit测试框架,则是正规android开发的必用技术,在Junit中可以得到组件,可以模拟发送事件和检测程序处理的正确性. 比如,若想验证一个自定义类中的某个方法时,则可以在单元测试中创建这个类对象,并给定适合参数调用该类方法. Android单元测试具体方法如下: (1).创建一个类继承AndroidTestCase,该类为一个单元测试类. (2).在AndroidMainfest中声明instrumentation分支.

Android单元测试时如何使用log查看输出结果

Android单元测试与日志输出:http://blog.csdn.net/xy849288321/article/details/7054790

Android单元测试初探——Instrumentation(转载)

学习Android有一段时间了,虽然前段时间对软件测试有了一些了解,不过接触android的单元测试却是头一次.这几天在物流大赛上也用了不少时间,所以对于android的单元测试没有太深入的研究,所以先写个基本入门吧! 首先,我们来了解一下android的测试类的层次结构: 可以看出android中的测试方法主要有AndroidTextCase和InstrumentationTextCase.在这篇文章中,我将介绍Instrumentation这种测试方法,那么什么是Instrumentatio

如何进行Android单元测试

如何进行Android单元测试 Menifest.xml中加入: <application>中加入: <uses-library android:name="android.test.runner" /> <application>外面加入: <uses-permission android:name="android.permission.RUN_INSTRUMENTATION" /> <instrumenta

Android 单元测试学习计划

网上查了一下Android单元测试相关的知识点,总结了一个学习步骤: 1. 什么是单元测试2. 单元测试正反面: 2.1. 重要性 2.2. 缺陷 2.3. 策略3. 单元测试的基础知识: 3.1. 单元测试分类 3.2. 单元测试术语 3.3. 单元测试工具,框架4. 什么是junit5. 运行简单的Android单元测试简单,总结建立测试的流程6. 运行简单的功能测试,ui测试,单元测试7. Android单元测试类的层次结构8. 如何深入了解单元测试: 经验,技巧,总结

Android单元测试实践

为什么要写单元测试 首先要介绍为什么蘑菇街支付金融这边会采用单元测试的实践.说起来比较巧,刚开始的时候,只是我一个人会写单元测试.后来老板们知道了,觉得这是件 很有价值的事情,于是就叫我负责我们组的单元测试这件事情.就这样慢慢的,单元测试这件事情就成了我们这边的正常实践了.再后来,在公司层面也开始有一定 的推广. 要说为什么要写单元测试的话,我相信大部分人都能承认.也能理解单元测试在保证代码质量,防止bug或尽早发现bug这方面的作用,这可能 是大家觉得单元测试最大的作用.然而我觉得,除了这方面

android单元测试 activity跳转 以及 input 输入后 测试

Android junit实现多个Activity跳转测试 分类: Android Junit测试2011-11-14 16:49 1601人阅读 评论(2) 收藏 举报 androidjunitlayout测试单元测试exception 测试相关资源 让开发自动化: 用 Eclipse 插件提高代码质量http://www.ibm.com/developerworks/cn/java/j-ap01117/index.html 代码测试覆盖率介绍:http://www.cnblogs.com/c