Android 单元测试

单元测试测什么?

单元测试由一组独立的测试构成,每个测试针对软件中的一个单独的程序单元。单元测试并非检查程序单元之间是否能够合作良好,而是检查单个程序单元行为是否正确。
单元测试中进行测试工作的主要在5个方面:

1、模块接口测试:对被测模块的数据流进行测试,保证模块对各种输入的兼容以及正确的输出

  • 模块输入参数的数目是否与模块形式参数数目相同。
  • 模块各输入的参数属性与对应的形参属性是否一致。
  • 模块各输入的参数类型与对应的形参类型是否一致。
  • 传到被调用模块的实参的数目是否与被调用模块形参的数目相同。
  • 传到被调用模块的实参的属性是否与被调用模块形参的属性相同。
  • 传到被调用模块的实参的类型是否与被调用模块形参的类型相同。
  • 引用内部函数时,实参的次序和数目是否正确。
  • 是否引用了与当前入口无关的参数。
  • 用于输入的变量有没有改变。
  • 在经过不同模块时,全局变量的定义是否一致。
  • 限制条件是否以形参的形式传递。

当模块通过外部设备进行输入/输出操作时,必须扩展接口测试,附加如下的测试项目:

  • 文件的属性是否正确。
  • Open与Close语句是否正确。
  • 规定的格式是否与I/O语句相符。
  • 缓冲区的大小与记录的大小是否相配合。
  • 在使用文件前,文件是否打开。
  • 文件结束的条件是否安排好了。
  • I/O错误是否检查并做了处理。
  • 在输出信息中是否有文字错误。

2、局部数据结构测试

  • 不正确或不一致的数据类型说明。
  • 使用尚未赋值或尚未初始化的变量。
  • 错误的初始值或错误的默认值。
  • 变量名拼写错或书写错—— 使用了外部变量或函数。
  • 不一致的数据类型。
  • 全局数据对模块的影响。
  • 数组越界。
  • 非法指针。

3、路径测试:检查由于计算错误、判定错误、控制流错误导致的程序错误

在路径测试中,要检查的错误有:死代码,错误的计算优先级,算法错误,混用不同类的操作,初始化不正确,精度错误—— 比较运算错误、赋值错误,表达式的不正确符号—— >、>=;=、==、!=,循环变量的使用错误—— 错误赋值以及其他错误等

  • 不同数据类型的比较。
  • 不正确的逻辑运算符或优先次序。
  • 因浮点运算精度问题而造成的两值比较不等。
  • 关系表达式中不正确的变量和比较符。
  • “差 1 错”,即不正常的或不存在的循环中的条件。
  • 当遇到发散的循环时无法跳出循环。
  • 当遇到发散的迭代时不能终止循环。
  • 错误的修改循环变量。

4、错误处理测试:对可能引发错误处理的路径及进行错误处理的路径进行测试

  • 出错的描述是否难以理解,是否能够对错误定位。
  • 显示的错误与实际的错误是否相符;
  • 对错误条件的处理正确与否;
  • 在对错误进行处理之前,错误条件是否已经引起系统的干预等。

在进行错误处理测试时,要检查如下内容:

  • 在资源使用前后或其他模块使用前后,程序是否进行错误出现检查。
  • 出现错误后,是否可以进行错误处理,如引发错误、通知用户、进行记录。
  • 在系统干预前,错误处理是否有效,报告和记录的错误是否真实详细。

5、边界测试

  • 普通合法数据是否正确处理。
  • 普通非法数据是否正确处理。
  • 边界内最接近边界的(合法)数据是否正确处理。
  • 边界外最接近边界的(非法)数据是否正确处理等。
  • 在n次循环的第0次、第1次、第n次是否有错误。
  • 运算或判断中取最大最小值时是否有错误;
  • 数据流、控制流中刚好等于、大于、小于确定的比较值时是否出现错误。

单元测试框架

常见的有:Java单元测试框架JUnit、Java模拟测试框架Mockito、jMock、EasyMock、PowerMockito、Android单元测试框架Robolectric。除此之外还有一个google出的Espresso,前面几个都是在JVM下运行,这个必须在Android真机或虚拟机上跑,运行较慢(速度上:Java单元测试框架>Robolectric>Espresso)。无法集成到持续集成服务器上。
这里选择Robolectric+PowerMock,
Robolectric不仅支持UI组件的测试,同时支持日志输出、网络请求、数据库等方面的测试。并且Robolectric直接运行在JVM上,速度相对可以测试UI的框架快得多,相对基于JVM的框架慢一些,最关键是无需准备Android环境,能集成到服务器上。
PowerMock弥补了Mockito的几个缺点:不能mock静态、final、私有方法;基于JVM能集成到服务器上
Espresso能测试UI,使用相对简单成熟,缺点是需要Androd环境(即要跑在真机或者模拟器上)
这里的策略是:能用PowerMock做的单元测试(“纯Java”的代码基本都可以)则用PowerMoc提高速度,需要Android支持的时候用Robolectric,最终的目标是把单元测试集成到持续集成服务器上,每次push都可以跑单元测试并给出相应的结果报表。而Espresso则是在本地做一些UI测试(Robolectric问题较多,支持也不是特别好)

Robolectric

官网:http://robolectric.org/
github:https://github.com/robolectric/robolectric/
一个不错的例子:http://www.jianshu.com/p/9d988a2f8ff7
简单来讲,Robolectric可以提供大部分的UI测试以及四大组件+Fragment的模拟;同时提供Shadow来做一些扩展支持,ShadowActivtity、ShadowApplication、ShadowDialog等等是通过本尊映射一个影子,然后这个影子可以为我们提供更多的支持,比如我们可以通过ShadowActivity.getNextStartedActivity()在Activity跳转的时候获取即将跳转的Activity的类型。

Mockito

官网:http://site.mockito.org/
github:https://github.com/mockito/mockito
一个不错的中文介绍:https://github.com/hehonghui/mockito-doc-zh

PowerMock

基于Mockito
主要看下mock 静态、final、私有方法的例子

import org.junit.Assert;    
import org.junit.Test;    
import org.junit.runner.RunWith;    
import org.mockito.Mockito;    
import org.powermock.api.mockito.PowerMockito;    
import org.powermock.core.classloader.annotations.PrepareForTest;    
import org.powermock.modules.junit4.PowerMockRunner;    

@RunWith(PowerMockRunner.class)    
@PrepareForTest({ MyClass.class})//这里意思是测试带静态方法的类    
public class StaticClassSampleTest {    

    @Test    
    public void testPrivateMethod() throws Exception {    
        // 模拟 private的方法    
        MyClass spy = PowerMockito.spy(new MyClass());    
        PowerMockito.doReturn(3).when(spy, "private_method", 1);    
        Assert.assertEquals(3, spy.test_private_method(1));    
        PowerMockito.verifyPrivate(spy, Mockito.times(1)).invoke("private_method", 1);    
    }    

    @Test    
    public void testStaticReturnMethod() throws Exception {    
        // 模拟 静态有返回值的方法    
        PowerMockito.mockStatic(MyClass.class);    
        Mockito.when(MyClass.static_return_method()).thenReturn(2);    
        Assert.assertEquals(2, MyClass.static_return_method());    
    }    

    @Test    
    public void testVoidMethod() throws Exception {    
        // 模拟 不执行void的方法    
        MyClass spy = PowerMockito.spy(new MyClass());    
        PowerMockito.doNothing().when(spy).void_method();    
        spy.void_method();    
    }    

    @Test    
    public void testStaticMethod1() throws Exception {    
        // 模拟 不执行没参数的静态void的方法    
        PowerMockito.mockStatic(MyClass.class);    
        PowerMockito.doNothing().when(MyClass.class, "static_void_method");    
        MyClass.static_void_method();    
    }    

    @Test    
    public void testStaticMethod2() throws Exception {    
        // 模拟 不执行带参数的静态void的方法    
        PowerMockito.mockStatic(MyClass.class);    
        PowerMockito.doNothing().when(MyClass.class, "staticMethod", "123");    
        MyClass.staticMethod("123");    

        PowerMockito.doNothing().when(MyClass.class, "staticMethod", Mockito.anyString());    
        MyClass.staticMethod("456");    
    }    

}   

猜你喜欢

转载自blog.csdn.net/xiaoru5127/article/details/78390749