Android 开发 单元测试 (JUnit 4)

参考文章 : http://chriszou.com/2016/06/07/android-unit-testing-everything-you-need-to-know.html

什么是单元测试

简单的说: 单元测试是为了测试某一个代码单元而写的测试代码;

什么叫“一个代码单元”呢?是一个模块、还是一个类、还是一个方法(函数)呢?

在面向对象编程中,是为了测试某一个类的某一个方法能否正常工作,而写的测试代码。

  • 单元测试不是集成测试
    这里需要强调一个观念,那就是单元测试只是测试一个方法单元,它不是测试一整个流程。

  • 两种函数(方法),两种不同的测试方式
    一个类的方法可以分为两种,一种是有返回值的,另一种是没有返回值的。

为什么写单元测试

  • 首先跑一次单元测试总比运行一次app快
  • 写完一部分功能独立的代码,就能立刻看到他们是不是正确的
  • 减少大部分手工测试
  • 更快的发现bug
  • 并发现更多的bug
  • 测试驱动开发(TDD) ,提高开发效率
  • 觉的没有时间写测试代码?

怎么写单元测试

我们先不说测试代码怎么写,先搞清楚流程

刚才说了,单元测试是为了测试某一个类的某一个方法能否正常工作,而写的测试代码,
那我们写单元测试代码,就是给每一个java代码类的public方法写对应的测试代码;
那么非public方法怎么办呢, 一般来说,是不做处理的, 非public方法通常是类的内部实现细节,我们一般只关心public方法的的输入和输出;

一般来说写单元测试代码分为三个部分

  • 准备工作 : 一般先要new出你要的测试的类的对象
  • 执行操作 : 然后写测试代码
  • 验证结果 : 得到验证结果,看是否达到预期

注意事项: 单元测试不会接触到数据库,不会接触到网络,不会接触到一些复杂的外部环境,如果有的话,那可能是你测试的方式有误,测试的粒度不够“单元”

刚才上面说到

一个类的方法可以分为两种,一种是有返回值的,另一种是没有返回值的。

先说有返回值的

JUnit单元测试框架的使用

单元测试,一般都会用到一个或多个单元测试框架,在这里,我们介绍一下JUnit4这个测试框架。这是Java界用的最广泛,也是最基础的一个框架,其他的很多框架都是基于或兼容JUnit4的。

为什么要使用单元测试框架

首先你也可以不用测试框架, 手工写测试代码, java 中可以使用main方法执行测试代码,你可以自己写测试代码,然后执行

有下面的这段代码需要进行测试

   public Boolean loginApp(String name){
        if (name == "123456") {
            return true;
        }else {
            return false;
        }
    }

我们看看在不使用JUnit测试框架的情况下怎么怎么测试

public static void main(String[] args) {
        LoginPersenter loginPersenter = new LoginPersenter();
        Boolean aBoolean = loginPersenter.loginApp("123456");
        if(aBoolean == true) {
            System.out.println("登录成功了");
        } else {
            System.out.println("登录失败了");
        }
    }

那么我们使用JUnit测试框架的情况下

     @Test
    public void testAppLogin()  throws Exception{
        LoginPersenter loginPersenter = new LoginPersenter();
        Boolean aBoolean = loginPersenter.loginApp("123456");
         assertTrue(aBoolean);
    }

每一个被测试的方法,写一个对应的测试方法, 通过@Test注解来标识

先来看看JUnit注解

注解 描述
@Test public void method() 简单说就是用这个注解的代表的是一个测试用例
@Before public void method() Before注释表示,该方法必须在类中的每个测试之前执行,以便执行测试某些必要的先决条件。
@BeforeClass public static void method() BeforeClass注释指出这是附着在静态方法必须执行一次并在类的所有测试之前。发生这种情况时一般是测试计算共享配置方法(如连接到数据库)。
@After public void method() After 注释指示,该方法在执行每项测试后执行(如执行每一个测试后重置某些变量,删除临时变量等)
@AfterClass public static void method() 当需要执行所有的测试在JUnit测试用例类后执行,AfterClass注解可以使用以清理建立方法,(从数据库如断开连接)。注意:附有此批注(类似于BeforeClass)的方法必须定义为静态。
@Ignore public static void method() 当想暂时禁用特定的测试执行可以使用忽略注释。每个被注解为@Ignore的方法将不被执行。

然后看看JUnit断言

断言 描述
void assertEquals([String message], expected value, actual value) 断言两个值相等。值可能是类型有 int, short, long, byte, char or java.lang.Object. 第一个参数是一个可选的字符串消息
void assertTrue([String message], boolean condition) 断言一个条件为真
void assertFalse([String message],boolean condition) 断言一个条件为假
void assertNotNull([String message], java.lang.Object object) 断言一个对象不为空(null)
void assertNull([String message], java.lang.Object object) 断言一个对象为空(null)
void assertSame([String message], java.lang.Object expected, java.lang.Object actual) 断言,两个对象引用相同的对象
void assertNotSame([String message], java.lang.Object unexpected, java.lang.Object actual) 断言,两个对象不是引用同一个对象
void assertArrayEquals([String message], expectedArray, resultArray) 断言预期数组和结果数组相等。数组的类型可能是 int, long, short, char, byte or java.lang.Object.
fail() 让测试方法失败

看完这些东西 ,我们写个代码应用一下

先看一下等待测试的代码

package com.zhiguo.dagger2test;

/**
 * Created by TiaoPi on 2017/11/20.
 */

public class JUnitTest {

    public int testAdd(int a ,int b){
        return a + b;
    }

    public Boolean testEquals(int a ,int b){
        if (a == b) {
            return true;
        }else {
            return false;
        }
    }

}

然后看一下测试代码

@RunWith(AndroidJUnit4.class)
public class ExampleInstrumentedTest {

    JUnitTest jUnitTest;
    int testAddNum ;

    @Before
    public void setup() {
        jUnitTest = new JUnitTest();
        testAddNum = 2;
    }

    @After
    public void executedAfterEach(){
        testAddNum = 2;
    }

    @Test
    public void testAdd() throws Exception{
        int testAdd = jUnitTest.testAdd(1, 2);
        assertEquals(testAddNum + 1,testAdd);
//        assertEquals("测试得到的结果是不是" +testAddNum + 1 ,testAddNum + 1,testAdd);
    }

    @Test
    public void testAdd2() throws Exception{
        int testAdd = jUnitTest.testAdd(2, 2);
        assertEquals(testAddNum + 2,testAdd);
//        assertEquals("测试得到的结果是不是" +testAddNum + 2 ,testAddNum + 2,testAdd);
    }


    @Test
    public void testEquals()  throws Exception{
        Boolean aBoolean = jUnitTest.testEquals(1, 1);
        assertTrue(aBoolean);
//        assertTrue("测试得到的结果不是true",aBoolean);
    }

    @Test
    @Ignore("不让testIgnore方法执行")
    public void testIgnore() {
    }

}

开始执行

Android 开发 单元测试 (JUnit 4)_第1张图片
1f844e5d-4aeb-497f-989a-4693f8d05b56.png

执行完成后,没有问题的情况下

Android 开发 单元测试 (JUnit 4)_第2张图片
d69996ec-0b6b-46e6-9e04-077554724a93.png

我们搞几个问题出来

Android 开发 单元测试 (JUnit 4)_第3张图片
4964d84f-e022-4ab1-93e6-40b87ffd8317.png

其他的功能介绍

Ignore一些测试方法

让JUnit忽略某些方法,让它在跑所有测试方法的时候不要跑这个测试方法。要达到这个目的也很简单,只需要在要被忽略的测试方法前面加上@Ignore就可以了

    @Test
    @Ignore("不让testIgnore方法执行")
    public void testIgnore() {
    }
Android 开发 单元测试 (JUnit 4)_第4张图片
13592a67-cae4-4a21-ae6f-8ca32e656590.png

验证方法会抛出某些异常

有的时候,抛出异常是才能让一个方法正常运行。

比如我们现在有这样一段代码

 public int testExpected (int a){
        if (a == 1) throw new  IllegalArgumentException("这个值不能是1");
        return a;
    }

进行测试

    @Test(expected = IllegalArgumentException.class)
    public void testExpected (){
        jUnitTest.testExpected(1);
    }

当然啦,如果正确的抛出异常是说明代码没问题, 只有抛出异常的时候才会报错

接下来 我们考虑测试没有返回值的方法

你可能感兴趣的:(Android 开发 单元测试 (JUnit 4))