安卓006单元测试

来源:互联网 发布:popo聊天软件 编辑:程序博客网 时间:2024/05/18 03:29



Android 测试,日志

测试

常见测试分类
在介绍Android Junit前先介绍一下常见的测试分类。


根据是否知道源程序源码:


 黑盒测试:不知源码,只是测试程序的功能
 白盒测试:知道源码,根据源代码进行测试



根据测试的粒度:(模块的大小)


 单元测试:unit test
 功能测试:function test:方法测试
 整合测试:integration test:几个模块的测试,服务器/客户端的联调
 系统测试:system test



根据测试的次数:(暴力测试)


 冒烟测试:smoke test,不停的执行操作,直到系统崩溃

Google提供了一个monkey
Adb shell:进入模拟器目录,monkey
2000,通过monkey是随机点击2000次
monkey –p 包名 次数:只测试某个应用程序


 压力测试:pressure test



Junit  测试框架


运行测试代码:后台会帮我们做两步操作


上传当前应用程序到手机系统
发送指令通知手机测试刚才上传的代码


所以需要在清单文件里配置:
 添加指令集(manifest节点下)
<instrumentation
android:name="android.test.InstrumentationTestRunner"
android:targetPackage="com.example.sqlitephone" />

targetPackage:是测试目标包


 指令集依赖jar包(application节点下)
<uses-library android:name="android.test.runner" />




Junit  测试步骤



单元测试

   在实际开发中,开发android软件的过程需要不断地进行测试。而使用Junit  测试框架,则是正规的Android开发的必用技术,Android很好封装了Junit测试框架,可以模拟发送事件和检测程序处理的正确性

   * Android单元测试实现流程

     1.添加测试类库

       在AndroidManifest.xml 的<application> 节点 添加测试类库

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

     2.设置测试环境

       <instrumentationandroid:name="android.test.InstrumentationTestRunner"android:targetPackage="cn.itcast.filestore"/>

     3. 编写测试类

- 获取上下文getContext()- 继承AndroidTestCase

- 使用断言 assertEquals()

- 查看测试效果

我们完成了一个业务方法,想要对其进行测试,Android程序是不能写main
方法运行的,需要建测试项目


1. 创建测试项目
创建测试工程
定义工程名
选择要测试哪个工程

创建测试类,注意要继承AndroidTestCase
编写测试类
可以直接使用被测试工程中的业务类,测试方法必须以小写“test”开头

2. 不创建测试项目,加测试类
在AndroidManifest.xml清单文件中添加配置
< instrumentation android:targetPackage= "cn.itcast.junit"
android:name= "android.test.InstrumentationTestRunner" />
<uses-library android:name= "android.test.runner" />
定义一个类继承AndroidTestCase,定义测试方法


Junit  单元测试


 新建业务方法
例如计算器的加法:
// 计算器
public class Calc {
/**
* 计算器相加的方法
* @param x
* @param y
* @return
*/
public int add(int x, int y) {
return x + y;
}
}
 新建Junit测试类,对add方法进行单元测试

//Android中想要进行单元测试 需要继承AndroidTestCase
public class TestCalc extends AndroidTestCase{
//需要写一个测试方法
public void testAdd(){
//想测试 计算器相加的方法
Calc calc = new Calc();
int result = calc.add(5, 6);
//断言
assertEquals(11,result);
}
}
 在清单文件中添加测试指令
<!--测试需要改成我们自己应用的包 -->
<instrumentation
android:name="android.test.InstrumentationTestRunner"
android:targetPackage="com.itheima.unit"
android:label="Tests for My App" />
 运行测试方法testAdd
如图:双击方法,右键Run As——Android Junit Test
运行结果:绿条代表测试通过。


Junit 单元测试,在公司中会用到,所以大家需要掌握。

Android Junit 拓展知识
注意:拓展知识并不是必须要求掌握的,心有余力之时可以作为进一步提升的
参考。
Android
测试环境的核心是一个Instrumentation框架,在这个框架下,你的测试应用程序
可以精确控制应用程序。使用Instrumentation,
你可以在主程序启动之前,创建模拟的系统对象,如Context;控制应用程序的
多个生命周期;发送UI事件给应用程序;在执行期间检查程序状态。
Instrumentation框架通过将主程序和测试程序运行在同一个进程来实现这些功能

通过在测试工程的manifest文件中添
加<instrumentation>元素来指定要测试的应用程序。这个元素的特性指明了要测
试的应用程序包名,以及告诉Android如何运行测试程序。下面的图片概要的描
述了Android的测试环境:

Android中,测试程序也是Android程序,因此,它和被测试程序的书写方式有
很多相同的地方。SDK工具能帮助你同时创建主程序工程及它的测试工程。你
可以通过Eclipse的ADT插件或者命令行来运行Android测试。Eclipse的ADT提供
了大量的工具来创建测试用例,运行以及查看结果。
Android提供了基于JUnit测试框架的测试API来书写测试用例和测试程序。
另外,Android还提供了强大的Instrumentation框架,允许测试用例访问程序的
状态及运行时对象。


Android Junit 中的主要核心API
 JUnit TestCase类
继承自JUnit的TestCase,不能使用Instrumentation框架。但这些类包含
访问系统对象(如Context)的方法。使用
Context,你可以浏览资源,文件,数据库等等。基类是AndroidTestCase,一
般常见的是它的子类,和特定组件关联。
子类有:
 ApplicationTestCase——
测试整个应用程序的类。它允许你注入一个模拟的Context到应用程
序中,在应用程序启动之前初始化测试参数,并在应用程序结束之
后销毁之前检查应用程序。
 ProviderTestCase2——
测试单个ContentProvider的类。因为它要求使用MockContentResolve
r,并注入一个IsolatedContext,因此Provider的测试是与OS孤立的

 ServiceTestCase——
测试单个Service的类。你可以注入一个模拟的Context或模拟的Appl
ication(或者两者),或者让Android为你提供Context和MockApplic
ation。
 Instrumentation TestCase类
继承自JUnit
TestCase类,并可以使用Instrumentation框架,用于测试Activity。使用Instrument
ation,Android可
以向程序发送事件来自动进行UI测试,并可以精确控制Activity的启动,监测Ac
tivity生命周期的状态。
基类是InstrumentationTestCase。它的所有子类都能发送按键或触摸事件
给UI。子类还可以注入一个模拟的Intent。子类有:
 ActivityTestCase——Activity测试类的基类。
 SingleLaunchActivityTestCase——
测试单个Activity的类。它能触发一次setup()和tearDown(),而不是
每个方法调用时都触发。如果你的测试方法都是针对同一个Activity
的话,那就使用它吧。
黑马Android课程笔记 就业服务部出品
 SyncBaseInstrumentation——测试Content
Provider同步性的类。它使用Instrumentation在启动测试同步性之前
取消已经存在的同步对象。
 ActivityUnitTestCase——
对单个Activity进行单一测试的类。使用它,你可以注入模拟的Cont
ext或Application,或者两者。它用于对Activity进行单元测试。不同
于其它的Instrumentation类,这个测试类不能注入模拟的Intent。
 ActivityInstrumentationTestCase2——
在正常的系统环境中测试单个Activity的类。你不能注入一个模拟的
Context,但你可以注入一个模拟的Intent。另外,你还可以在UI线
程(应用程序的主线程)运行测试方法,并且可以给应用程序UI发
送按键及触 摸事件。
 Assert类
Android还继承了JUnit的Assert类,其中,有两个子类,MoreAsserts和Vi
ewAsserts。
 MoreAsserts类包含更多强大的断言方法,如assertContainsRegex(Stri
ng, String),可以作正则表达式的匹配。
 ViewAsserts类包含关于Android
View的有用断言方法,如assertHasScreenCoordinates(View, View,
int,
int),可以测试View在可视区域的特定X、Y位置。这些Assert简化
了UI中几何图形和对齐方式的测试。
 Mock对象类
Android
有一些类可以方便的创建模拟的系统对象,如Application,Context,Content
Resolver和Resource。Android还在一些测试类中提供了一些方法来创建模拟的In
tent。因为这些模拟的对象比实际对象更容易使
用,因此,使用它们能简化依赖注入。你可以在android.test和android.test.mock
中找到这些类。
它们是:
 IsolatedContext——
模拟一个Context,这样应用程序可以孤立运行。与此同时,还有大
量的代码帮助我们完成与Context的通信。这个类在单元测试时很有
用。
黑马Android课程笔记 就业服务部出品
 RenamingDelegatingContext——
当修改默认的文件和数据库名时,可以委托大多数的函数到一个存
在的、常规的Context上。使用这个类来测试文件和数据库与正常的
系统Context之间的操作。
 MockApplication,MockContentResolver,MockContext,MockDialogInter
face,MockPackageManager,MockResources ——
创建模拟的系统对象的类。它们只暴露那些对对象的管理有用的方
法。这些方法的默认实现只是抛出异常。你需要继承这些类并重写
这些方法。
 Instrumentation TestRunner
Android
提供了自定义的运行测试用例的类,叫做InstrumentationTestRunner。这个类控
制应用程序处于测试环境中,在同一个进程中运行测试
程序和主程序,并且将测试结果输出到合适的地方。IntrumentationTestRunner
在运行时对整个测试环境的控制能力的关键是使用
Instrumentation。注意,如果你的测试类不使用Instrumentation的话,你也可以
使用这个TestRunner。
当你运行一个测试程序时,首先会运行一个系统工具叫做Activity
Manager。Activity
Manager使用Instrumentation框架来启动和控制TestRunner,这个TestRunner反过
来又使用
Intrumentation来关闭任何主程序的实例,然后启动测试程序及主程序(同一个
进程中)。这就能确保测试程序与主程序间的直接交互。
在测试环境中工作
对Android程序的测试都包含在一个测试程序里,它本身也是一个Android
应用程序。测试程序以单独的Android工程存在,与正常的Android程序有着相
同的文件和文件夹。测试工程通过在manifest文件中指定要测试的应用程序。
每个测试程序包含一个或多个针对特定类型组件的测试用例。测试用例里
定义了测试应用程序某些部分的测试方法。当你运行测试程序,Android会在相
同进程里加载主程序,然后触发每个测试用例里的测试方法。
测试工程
为了开始对一个Android程序测试,你需要使用Android工具创建一个测试
工程。工具会创建工程文件夹、文件和所需的子文件夹。工具还会创建一个ma
nifest文件,指定被测试的应用程序。
黑马Android课程笔记 就业服务部出品
测试用例
一个测试程序包含一个或多个测试用例,它们都继承自Android
TestCase类。选择一个测试用例类取决于你要测试的Android组件的类型以及你
要做什么样的测试。一个测试程序可以测试不同的组件,但每个测试用例类设
计时只能测试单一类型的组件。
一些Android组件有多个关联的测试用例类。在这种情况下,在可选择的
类间,你需要判断你要进行的测试类型。例如,对于Activity来说,你有两个选
择,ActivityInstrumentationTestCase2和ActivityUnitTestCase。
ActivityInstrumentationTestCase2设计用于进行一些功能性的测试,因此
,它在一个正常的系统环境中测试Activity。你可以注入模拟的Intent,但不能
是模拟的Context。一般来说,你不能模拟Activity间的依赖关系。相比而言,A
ctivityUnitTestCase设计用于单元测试,因此,它在一个孤立的系统环境中测试
Activity。换句话说,当你使用这个测试类时,Activity不能与其它Activity交互

作为一个经验法则,如果你想测试Activity与Android的交互的话,使用Acti
vityInstrumentationTestCase2。如果你想对一个Activity做回归测试的话,使用Ac
tivityUnitTestCase。
测试方法
每个测试用例类提供了可以建立测试环境和控制应用程序的方法。例如,
所有的测试用例类都提供了JUnit的setUp()方法来搭建测试环境。另外,你可以
添加方法来定义单独的测试。当你运行测试程序时,每个添加的方法都会运行
一次。如果你重写了setUp()方法,它会在每个方法运行前运行。相似
的,tearDown()方法会在每个方法之后运行。
测试用例类提供了大量的对组件启动和停止控制的方法。由于这个原因,
在运行测试之
前,你需要明确告诉Android启动一个组件。例如,你可以使用getActivity()来启
动一个Activity。在整个测试用例期间,你只能调
用这个方法一次,或者每个测试方法一次。甚至你可以在单个测试方法中,调
用它的finishing()来销毁Activity,然后再调用 getActivity()重新启动一个。
运行测试并查看结果
编译完测试工程后,你就可以使用系统工具Activity
Manager来运行测试程序。你给Activity
Manager提供了TestRunner的名(一般是InstrumentationTestRunner,在程序中指
定);名包括被测试程序的包名和 TestRunner的名。Activity
Manager加载并启动你的测试程序,杀死主程序的任何实例,然后在测试程序的
同一个进程里加载主程序,然后传递测试程序的第一个测试用例。这个时
候,TestRunner会接管这些测试用例,运行里面的每个测试方法,直到所有的
方法运行结束。
黑马Android课程笔记 就业服务部出品
如果你使用Eclipse,结果会在JUnit的面板中显示。如果你使用命令行,
将输出到STDOUT上。
测试什么?
除了一些功能测试外,这里还有一些你应该考虑测试的内容:
Activity生命周期事件:你应该测试Activity处理生命周期事件的正确性。例如,
一个Activity应该在pause或destroy事件
时保存它的状态。记住一点的是屏幕方向的改变也会引发当前Activity销毁,因
此,你需要测试这种偶然情况确保不会丢失应用程序状态。
数据库操作:你应该确保数据库操作能正确处理应用程序状态的变化。使用and
roid.test.mock中的模拟对象。
屏幕大小和分辨率:在发布程序之前,确保在所有要运行的屏幕大小和分辨率
上测试通过。你可以使用AVD来测试,或者使用真实的目标设备进行测试。
UI 线程中测试
Activity运行在程序的UI线程里。一旦UI初始化后,例如在Activity的onCrea
te()方法后,所有与UI的交互都必须运行在UI线程里。当你正常运行程序时,它
有权限可以访问这个线程,并且不会出现什么特别的事情。当你运行测试程序
时,这一点发生了变化。在带有instrumentation的类里,你可以触发方法在UI线
程里运行。其它的测试用例类不允许这么做。
为了一个完整的测试方法都在UI线程里运行,你可以使用@UIThreadTest来
声明线程。注意,这将会在UI线程里运行方法里所有的语句。不与UI交
互的方法不允许这么做;例如,你不能触发Instrumentation.waitForIdleSync()。
如果让方法中的一部分代码运行在UI线程的话,创建一个匿名的Runnabl
e对象,把代码放到run()方法中,然后把这个对象传递给appActivity.runOnUiThr
ead(),在这里,appActivity就是你要测试的app对象。



日志信息
LogCat 介绍
Android
LogCat的获取有两种方式:1、DDMS提供的LogCat视图2、通过adb命令行
 DDMS提供的LogCat视图如下

如果该视图没有打开,点击window->show view->other->android-
>Logcat来进行选择。
视图的左侧可以选择或者添加过滤信息,运行一个应用程序时,此处会默
认创建一个该包的过滤。视图的右上角区域用于选择LogCat的log级别,共有ver
bose、debug、info、warn、error、assert6个可选项。如图所示:

该视图的主体部分是log的详细信息,包括错误级别(Level)、时间(Tim
e)、进程ID(PID)、线程ID(TID)、应用程序包名(Application)、标签(
Tag)、日志正文(Text)。
其中的TID并不等同于Java中的Thread.currentThread().getId(),而是我们Linux
中的Thread ID,跟PID相同。
 通过命令行调用LogCat
 将LogCat信息显示在控制台中
在控制台中输入adb logcat
然后按回车键即可看到LogCat信息,如果需要终止按Ctrl+C键即可。
 将LogCat信息保存在文件中

执行adb logcat >D:/a.txt
则将日志输出到D:/a.txt文件中。按Ctrl+C键终止日志的输出。
上面介绍的只是adb
logcat命令的最简单用法,其实该命令还有多种可选参数供选择,这里就不再详
细说明。


Logcat 的日志等级
android.util.Log常用的方法有以下5个:
Log.v() Log.d() Log.i() Log.w() 以及 Log.e() 。根据首字母对应VERBOSE
,DEBUG,INFO, WARN ,ERROR。
 Log.v
的调试颜色为 黑色的,任何消息都会输出,这里的v代表verbose啰嗦的意思
,平时使用就是Log.v("","");
 Log.d的输出颜色是 蓝色的,仅输出debug调试的意思,但他会输出上层的信
息,过滤起来可以通过DDMS的Logcat标签来选择.
 Log.i的输出为 绿色,一般提示性的消息information,它不会输出Log.v和Log
.d的信息,但会显示i、w和e的信息,System.out输出信息是Info级别
 Log.w的意思为 橙色,可以看作为warning警告,一般需要我们注意优化And
roid代码,同时选择它后还会输出Log.e的信息。
 Log.e为红色,可以想到error错误,这里仅显示红色的错误信息,这些错误
就需要我们认真的分析,查看栈的信息了。
 程序中我们可以使用Log类来输出信息

结果:
Logcat 通过tag 过滤
tag:可以利用tag进行过滤,用于查找日志。
在logcat中可以添加一个日志过滤器,选择日志等级,会显示出当前等级和比当
前等级高的等级。选择warn,会出现warn和error两种日志。还可以使用System.
out来打印日志(info级别),System.error(警告级别)
Logcat 日志激活
激活日志,ddms中随便点击devices中的一项即可。其实日志是打印在模拟器里
的,系统通过adb,将日志信息传递到开发平台的logcat中
如果还是没有打印日志,就重启adb或eclipse,然后也可以通过命令adb
logcat,可在cmd中查看日志

案例-Android 程序获取LogCat 信息
下面通过创建一个Android工程来演示如何在代码中实时获取LogCat信息。




 创建一个新工程,这里工程名为LogCat
在这个工程中使用默认的MainActivity.java类和默认的布局文件。
 修改布局文件
<LinearLayout
xmlns:android= "http://schemas.android.com/apk/res/android"
xmlns:tools= "http://schemas.android.com/tools"
android:layout_width= "match_parent"
android:layout_height= "match_parent"
android:orientation= "vertical"
tools:context= ".MainActivity" >
<Button
android:layout_width= "wrap_content"
android:layout_height= "wrap_content"
android:text= "获取LogCat"
android:id= "@+id/bt_click"
/>
<TextView
android:id= "@+id/tv_show"
android:layout_width= "match_parent"
android:layout_height= "wrap_content"
android:hint= "显示日志"
/>
</LinearLayout>

 修改MainActivity.java代码
代码第一部分:
package com.itheima.com.logcat;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
public class MainActivity extends Activity {
protected static final String TAG = "MyTest";
private Button btn;
private TextView tv_show;
private Handler handler = new Handler() {
public void handleMessage(android.os.Message msg) {
tv_show.setText((String) msg.obj);
};
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btn = (Button) findViewById(R.id.bt_click);
tv_show = (TextView) findViewById(R.id.tv_show);
黑马Android课程笔记 就业服务部出品
代码第二部分:
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.v(TAG, "这是verbose信息");
Log.d(TAG, "这是debug信息");
Log.i(TAG, "这是info信息");
Log.w(TAG, "这是warn信息");
Log.e(TAG, "这是error信息");
/** 开启线程用于监听log输出的信息 **/
new Thread(new Runnable() {
@Override
public void run() {
Process mLogcatProc = null;
BufferedReader reader = null;
try {
/*
*
通过执行命令行获取LogCat信息
*/
mLogcatProc =
Runtime.getRuntime().exec(new String[] { "logcat", TAG + ":v *:s"
});
/*
* 获取进程输出流对象
*/
reader = new
BufferedReader(new
InputStreamReader(mLogcatProc.getInputStream()));
String line = null;
StringBuilder sb = new
StringBuilder();

代码第三部分(完):
while ((line = reader.readLine()) != null) {
sb.append(line);
Message msg =
Message.obtain();
msg.obj =
sb.toString();
handler.sendMessage(msg);
}
reader.close();
/*
*
通过发送消息,通知主线程修改TextView对象
*
因此这个操作是在子线程中进行的,而Android应用中子线程是无法修改UI(UI的修改
操作必须在
* 主线程中进行
*
,因此Android提供了Handler机制,让子线程发送消息给主线程,然后由主线程修改U
I).
*/
} catch (Exception e) {
e.printStackTrace();
}
}
}).start();
}
});
}
}


 将项目运行在模拟器上,并点击按钮
运行结果如图所示:
结合工作和面试
 面试中
 Junit测试
面试中有可能会被问到,你们公司以前是怎么去测试的?
你可以说我们公司比较规范,有的功能会用Junit测试。也可以说,
我们就是手工测试,自己测试没问题了,提交给测试人员去测试。
然后他们提交bug,我们修复。
 日志信息
面试中,会被问到,你是怎么解决bug的?
一般说下,断点调试,变量分析,日志跟踪即可。
变量分析就是断点调试过程中,对变量的值进行监控,看是否为null
,或者不正常。
 工作中
 Junit测试

这个会使用即可,一般的小公司不会让做Junit测试,就是手测。大
公司,制度比较严格的可能会要求做Junit测试。要做也是一般的单
元测试,所以大家单元测试需要掌握。
主要还是测试人员写测试用例去测。
 日志信息
上边也提到过了,这个比较重要,一定要会看日志信息,对代码分
析,bug调试很有帮助。
还有就是有些同学的日志有时候出现不了,参照Logcat日志激活,
一般就是设备没连接成功,连接后有可能需要选择一下连接的设备






0 0
原创粉丝点击