android单元测试通过后,Android单元测试(四):JUnit介绍

JUnit是java开发人员的一个主要的测试工具,做Android开发同样是离不开java的,所以Android单元测试依然可以基于JUnit来写测试。但是JUnit只能运行在纯java环境上,前面我们介绍过MVP架构下,可以将View层隔离开来,单独针对Presenter层、Model层来测试。

4.1 JUnit4配置

在build.gradle中加入依赖配置,采用JUnit4框架。

testCompile 'junit:junit:4.12'

JUnit文件夹在工程中的位置,工程创建后,在app -> src目录下,会有3个文件夹:androidTest, main, test。test文件目录就是JUnit单元测试默认的目录。

06124ddc6c68

创建工程时,默认会生成一个单元测试例子ExampleUnitTest.java,且看看一个最简单的Junit单元测试是怎么写的:

public class ExampleUnitTest {

@Test

public void addition_isCorrect() throws Exception {

assertEquals(4, 2 + 2);

}

}

里面只有一个测试方法,方法上有一个@Test注解,选中方法名,右键选中“Run 'addition_isCorrect()'”执行单元测试,会出现执行结果:

06124ddc6c68

“OK”表示单元测试运行通过,到这里我们已经在Android上执行了一次单元测试。

4.2 JUnit4基础方法注解

JUnit3是通过对测试类和测试方法的命名来确定是否是测试,如测试方法必须以test开头。而在JUnit4中,是通过注解来确定的。

@Test

说明该方法是测试方法。测试方法必须是public void,可以抛出异常。

@Before

它会在每个测试方法执行前都调用一次。

@After

与@Before对应,它会在每个测试方法执行完后都调用一次。

@BeforeClass

它会在所有的测试方法执行之前调用一次。与@Before的差别是:@Before注解的方法在每个方法执行前都会调用一次,有多少个测试方法就会掉用多少次;而@BeforeClass注解的方法只会执行一次,在所有的测试方法执行前调用一次。注意该注解的测试方法必须是public static void修饰的。

@AfterClass

与@BeforeClass对应,它会在所有的测试方法执行完成后调用一次。注意该注解的测试方法必须是public static void修饰的。

@Ignore

忽略该测试方法,有时我们不想运行某个测试方法时,可以加上该注解。

以上这些注解都是针对测试方法而言的,并且是一些常用的注解,我们会频繁用到。我们写个测试类来运行一下,看看具体的执行顺序,代码如下:

public class TestJUnitLifeCycle {

@BeforeClass

public static void init() {

System.out.println("------init()------");

}

@Before

public void setUp() {

System.out.println("------setUp()------");

}

@After

public void tearDown() {

System.out.println("------tearDown()------");

}

@AfterClass

public static void finish() {

System.out.println("------finish()------");

}

@Test

public void test1() {

System.out.println("------test1()------");

}

@Test

public void test2() {

System.out.println("------test2()------");

}

}

执行后打印结果如下:

------init()------

------setUp()------

------test1()------

------tearDown()------

------setUp()------

------test2()------

------tearDown()------

------finish()------

4.3 JUnit4常用断言

JUnit提供了一些辅助函数,他们用来帮助我们确定被测试的方法是否按照预期正常执行,这些辅助函数我们称之为断言(Assertion)。JUnit4所有的断言都在org.junit.Assert类中,Assert类包含了一组静态的测试方法,用于验证期望值expected与实际值actual之间的逻辑关系是否正确,如果不符合我们的预期则表示测试未通过。

assertEquals([message], expected, actual)

验证期望值与实际值是否相等,如果相等则表示测试通过,不相等则表示测试未通过,并抛出异常AssertionError。message表示自定义错误信息,为可选参数,以下均雷同。

assertNotEquals([message], unexpected, actual)

验证期望值与实际值不相等。

assertArrayEquals([message], expecteds, actuals)

验证两个数组是否相同

assertSame([message], expected, actual)

断言两个引用指向同一个对象。

assertNotSame([message], expected, actual)

断言两个引用指向不同的对象。

assertNull([message], object)

断言某个对象为null。

assertNotNull([message], object)

断言对象不为null。

assertTrue([message], condition)

断言条件为真。

assertFalse([message], condition)

断言条件为假。

4.4 Hamcrest与assertThat

Hamcrest是一个表达式类库,它提供了一套匹配符Matcher,且看其官网的说明:

Hamcrest is a library of matchers, which can be combined in to create flexible expressions of intent in tests. They've also been used for other purposes.

前面提到的那些断言方法,大家使用起来会可能会碰到一个问题:

断言通常必须使用一个固定的expected值,如果测试数据稍微有一点变化,测试就可能不通过,这使得测试非常脆弱。例如我们断言assertEquals(0, code),只能判断code是不是为0,如果code不等于0则测试失败,如果code = 0或者 code = 1都是符合我的预期的呢?那又该如何测试。

JUnit4结合Hamcrest提供了一个全新的断言语法:assertThat,结合Hamcrest提供的匹配符,可以表达全部的测试思想,上面提到的问题也迎刃而解。

使用gradle引入JUnit4.12时已经包含了hamcrest-core.jar、hamcrest-library.jar、hamcrest-integration.jar这三个jar包,所以我们无需额外再单独导入hamcrest相关类库。

assertThat定义如下:

public static void assertThat(String reason, T actual,

Matcher super T> matcher)

4.4.1 字符串相关匹配符

startsWith

endsWith

containsString

equalToIgnoringCase

equalToIgnoringWhiteSpace

4.4.2 数值相关匹配符

closeTo

greaterThan

lessThan

lessThanOrEqualTo

greaterThanOrEqualTo

4.4.3 集合相关匹配符

hasEntry

hasKey

hasValue

hasItem

hasItems

hasItemInArray

4.4.4 对象相关匹配符

notNullValue

nullValue

sameInstance

instanceOf

hasProperty

4.4.5 组合等逻辑匹配符

allOf

anyOf

both

either

is

isA

not

any

anything

//文本

assertThat("android studio", startsWith("and"));

assertThat("android studio", endsWith("dio"));

assertThat("android studio", containsString("android"));

assertThat("android studio", equalToIgnoringCase("ANDROID studio"));

assertThat("android studio ", equalToIgnoringWhiteSpace(" android studio "));

//数字

//测试数字在某个范围之类,10.6在[10.5-0.2, 10.5+0.2]范围之内

assertThat(10.6, closeTo(10.5, 0.2));

//测试数字大于某个值

assertThat(10.6, greaterThan(10.5));

//测试数字小于某个值

assertThat(10.6, lessThan(11.0));

//测试数字小于等于某个值

assertThat(10.6, lessThanOrEqualTo(10.6));

//测试数字大于等于某个值

assertThat(10.6, greaterThanOrEqualTo(10.6));

//集合类测试

Map map = new HashMap();

map.put("a", "hello");

map.put("b", "world");

map.put("c", "haha");

//测试map包含某个entry

assertThat(map, hasEntry("a", "hello"));

//测试map是否包含某个key

assertThat(map, hasKey("a"));

//测试map是否包含某个value

assertThat(map, hasValue("hello"));

List list = new ArrayList();

list.add("a");

list.add("b");

list.add("c");

//测试list是否包含某个item

assertThat(list, hasItem("a"));

assertThat(list, hasItems("a", "b"));

//测试数组是否包含某个item

String[] array = new String[]{"a", "b", "c", "d"};

assertThat(array, hasItemInArray("a"));

//测试对象

//测试对象不为null

assertThat(new Object(), notNullValue());

Object obj = null;

//测试对象为null

assertThat(obj, nullValue());

String str = null;

assertThat(str, nullValue(String.class));

obj = new Object();

Object obj2 = obj;

//测试2个引用是否指向的通一个对象

assertThat(obj, sameInstance(obj2));

str = "abc";

assertThat(str, instanceOf(String.class));

//测试JavaBean对象是否有某个属性

assertThat(new UserInfo(), hasProperty("name"));

assertThat(new UserInfo(), hasProperty("age"));

//-------组合逻辑测试--------

//两者都满足,a && b

assertThat(10.4, both(greaterThan(10.0)).and(lessThan(10.5)));

//所有的条件都满足,a && b && c...

assertThat(10.4, allOf(greaterThan(10.0), lessThan(10.5)));

//任一条件满足,a || b || c...

assertThat(10.4, anyOf(greaterThan(10.3), lessThan(10.4)));

//两者满足一个即可,a || b

assertThat(10.4, either(greaterThan(10.0)).or(lessThan(10.2)));

assertThat(10.4, is(10.4));

assertThat(10.4, is(equalTo(10.4)));

assertThat(10.4, is(greaterThan(10.3)));

str = new String("abc");

assertThat(str, is(instanceOf(String.class)));

assertThat(str, isA(String.class));

assertThat(10.4, not(10.5));

assertThat(str, not("abcd"));

assertThat(str, any(String.class));

assertThat(str, anything());

4.5 测试方法执行顺序

当我们运行一个测试类里的所有测试方法时,测试方法的执行顺序并不是固定的,JUnit4提供@ FixMethodOrder注解来配置执行顺序,其可选值有:MethodSorters.NAME_ASCENDING、MethodSorters.DEFAULT、MethodSorters.JVM

@FixMethodOrder(MethodSorters.NAME_ASCENDING)

public class TestExecOrder {

@Test

public void testD() {

System.out.println("DDDDD");

}

@Test

public void testA() {

System.out.println("AAAAA");

}

@Test

public void testB() {

System.out.println("BBBBB");

}

@Test

public void testC() {

System.out.println("CCCCC");

}

}

@FixMethodOrder(MethodSorters.NAME_ASCENDING)执行结果(按名称升序排列):

AAAAA

BBBBB

CCCCC

DDDDD

@FixMethodOrder(MethodSorters.JVM)执行结果(每次执行可能都不一样):

CCCCC

DDDDD

AAAAA

BBBBB

4.6 小结

本文介绍了JUnit4在android开发中怎样配置,JUnit的基本用法,JUnit常用的断言机制,以及与Hamcrest结合起来的强大的assertThat断言,这些功能基本上能满足我们绝大部分的单元测试编写。

接下来还会再介绍JUnit里更好玩的、更高级的用法。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值