Android中如何简单的做单元测试

版权声明:本文为博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/JavaAndroid730/article/details/53327276

单元测试

单元测试(模块测试)是开发者编写的一小段代码,用于检验被测代码的一个很小的、很明确的功能是否正确。通常而言,一个单元测试是用于判断某个特定条件(或者场景)下某个特定函数的行为。例如,你可能把一个很大的值放入一个有序list 中去,然后确认该值出现在list 的尾部。或者,你可能会从字符串中删除匹配某种模式的字符,然后确认字符串确实不再包含这些字符了。

基于JUnit 来进行测试,包括运行在JVM上的本地单元测试,和运行在Android设备上的Instrumented测试。

JUnit

把单元测试或集成测试类写成JUnit 4测试类。此框架提供了便捷的方法来执行测试中常见的建立(setup),拆除(teardown)和断言(assertion)操作。

一个基本的JUnit 4测试类是一个包含一个或多个测试方法的Java类。测试方法应以@Test注解开始,并包含代码执行和验证单一的功能,这通常是待测组件中的一个业务逻辑单元。

一:基本流程

  1. 写测试类
  2. 写测试方法
  3. 运行JUnit Test进行测试

二:注解方式

在你的JUnit测试类中,你可以使用下面的注解,来对你测试代码的片段做特殊处理:

@Before:使用此注解来指定一段代码为建立(setup)操作。测试类会在每一个测试方法之前调用此代码块。你可以有多个@Before注解的方法,但测试类调用这些方法的顺序无法保证。

@After:使用此注解来指定一段代码为拆除(teardown)操作。测试类会在每一个测试方法之后调用此代码块。同样,你可以在测试代码中定义多个@After操作。使用此注解释放内存资源。

@Test:使用此注解来标注测试方法。一个测试类可以包含多个测试方法,都以此注解开头,返回值为void

@Rule:Rule能以一种可重用的方式,灵活地添加或重定义每一个测试方法的行为。在Android测试中,此注解是和Android Testing Support Library提供的测试规则类结合起来使用,例如ActivityTestRule或者ServiceTestRule。

@BeforeClass:使用此注解标明测试类只会调用一次的静态方法。此步骤对于昂贵的操作(例如连接到数据库)是很有用的。

@AfterClass:使用此注解标明,在所有测试方法执行完毕后,会执行一次的静态方法。这一步骤中,应释放在@BeforeClass代码块中分配的资源。

@Test(timeout=):一些注解支持设置参数。例如,你可以为测试方法指定一个超时时间。如果测试没有在指定时间内介绍,它会自动失败。超时时间以毫秒为单位,例如@Test(timeout=5000)。

执行顺序为:@BeforeClass --> @Before --> @Test --> @After --> @AfterClass

使用JUnit的断言(Assert)类来验证对象状态的正确性。断言方法会比较你预期的值和测试得到的实际值,如果不符则会抛出异常。Assertion classes描述了这些方法的细节。

三:断言方法

常用的断言方法:

assertEquals(args):根据传入的参数判断预期结果和实际结果是否相等。

assertTrue/False(args): 判断一个条件为true/false。

assertNotNull/Null(args): 判断一个对象是否为空。

assertSame/NotSame(args): 判断两个对象是否指向同一个对象。

fail(args): 中断测试方法,可以为其设置信息。

四:测试示例

Android studio 默认支持JUnit,创建一个新的项目,项目中自动添加了JUnit的依赖testCompile 'junit:junit:4.12',所以可以直接在Android studio中使用JUnit来进行单元测试。

本地单元测试

运行在本地JVM上的单元测试,主要的测试类在路径src/test下(Project面板视图)。

第一步:项目中的被测试类: 确定一个被测试的类,测试里面的方法运行返回是否符合功能要求,比如在网络请求的时候,测试接口构建是否正确。

// 要被测试的接口或类
public interface RetrofitApi {

@GET("https://api.github.com/users/gqq")
Call<ResponseBody> getRequest();

@POST("/Handler/UserHandler.ashx?action=register")
Call<UserResult> getUserRequest(@Body User user);
}

第二步:创建测试类: 确定要被测试的类之后,在test路径下创建相应的测试类和测试方法来进行测试,而更快捷的方式在该类上点击右键菜单--> Go To --> Test(ctrl+shift+T快捷键),自动创建相应的测试类和方法,创建到test路径下

第三步:完善测试类和方法:

测试类和测试方法创建完成之后,在相应的方法中完善测试方法:

public class RetrofitApiTest {

    private RetrofitApi retrofitApi;

    // @Before 在测试方法执行之前被调用
    @Before
    public void setUp() throws Exception {
        retrofitApi = RetrofitClient.getInstance().getRetrofitApi();
    }

    // 测试方法
    @Test
    public void getRequest() throws Exception {
        ResponseBody body = retrofitApi.getRequest().execute().body();
        assertNotNull(body);
    }

    // 测试方法
    @Test
    public void getUserRequest() throws Exception {
        UserResult userResult = retrofitApi.getUserRequest(new User("123", "123")).execute().body();
        assertEquals(1,userResult.getCode());
    }

    // 测试完成后执行
    @After
    public void tearDown() throws Exception {

    }
}

第四步:执行测试类及结果: 右键Run "RetrofitApiTest"执行测试类,查看测试的结果。 

通过则显示为OK,未通过展示信息:

java.lang.AssertionError: 
Expected :1
Actual   :2

根据测试未通过信息进行修改。以上就是一次本地单元测试过程。

Instrumented单元测试

虽然在Android框架内支持运行instrumentation测试,但是目前开发重心主要集中在刚刚发布的作为Android Testing Support Library一部分的新的AndroidJUnitRunner,测试库包含Espresso,用于运行功能UI测试的框架。

第一步:添加依赖: 在gradle2.2默认添加了对单元测试的支持

androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
    exclude group: 'com.android.support', module: 'support-annotations'
})

android {
    defaultConfig {
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    }   
}   

所以不再进行依赖的添加。 没有默认添加依赖的话,需要手动添加以下依赖:

dependencies {
    androidTestCompile 'com.android.support.test:runner:0.4'
    // Set this dependency to use JUnit 4 rules
    androidTestCompile 'com.android.support.test:rules:0.4'
    // Set this dependency to build and run Espresso tests
    androidTestCompile 'com.android.support.test.espresso:espresso-core:2.2.1'
    // Set this dependency to build and run UI Automator tests
    androidTestCompile 'com.android.support:support-annotations:24.2.0'
}


android {
    defaultConfig {
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    }   
}   

具体参见:Testing Support Library Setup

第二步:确定要被测试的具有交互效果的页面:

例如注册页面,实现输入用户名和密码,点击注册按钮执行业务。

@Bind(R.id.et_Username)
EditText etUsername;
@Bind(R.id.et_Passrword)
EditText etPassrword;

@OnClick(R.id.btn_Register)
public void onClick() {
    // 执行业务
}

第三步:创建测试类和测试方法: 在要被测试的类中点击右键菜单--> Go To --> Test(ctrl+shift+T快捷键),自动创建相应的测试类和方法,创建到androidTest路径下。

第四步:完善测试类和测试方法:

import static android.support.test.espresso.Espresso.onView;
import static android.support.test.espresso.action.ViewActions.click;
import static android.support.test.espresso.action.ViewActions.typeText;
import static android.support.test.espresso.matcher.ViewMatchers.withId;

public class RetrofitPostActivityInstrumentedTest {

    @Rule
    public ActivityTestRule<RetrofitPostActivity> activityTestRule = new ActivityTestRule<RetrofitPostActivity>(RetrofitPostActivity.class);

    @Test
    public void onClick() throws Exception {

        onView(withId(R.id.et_Username)).perform(typeText("123456"));// 为id为et_Username的控件输入字符串“123456”

        onView(withId(R.id.et_Passrword)).perform(typeText("123456"));// 为id为et_Passrword的控件输入字符串“123456”

        onView(withId(R.id.btn_Register)).perform(click());// 为id为btn_Register的控件设置点击事件

        Thread.sleep(3000);// 因为注册为网络请求(耗时操作),所以线程休眠以等待结果。
    }
}

关于视图的操作方法由Espresso进行,更多API参考Espresso

第五步:执行测试

右键Run "RetrofitPostActivityInstrumentedTest"执行测试类,查看测试。 至此,测试过程结束。


展开阅读全文

没有更多推荐了,返回首页