热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

安卓单元测试(八):JunitRule的使用

JUnitRule是什么一个JUnitRule就是一个实现了TestRule的类,这些类的作用类似于@Before、@After,是用来在每个测试方法的执行前后执行一些代码的一个方

JUnit Rule是什么

一个JUnit Rule就是一个实现了TestRule的类,这些类的作用类似于@Before@After,是用来在每个测试方法的执行前后执行一些代码的一个方法。
如果你不清楚@Before@After这些Annotation的意思,Chances are你还不了解Junit的使用,建议先看这篇文章。
那为什么不直接用这些annotation呢?这是因为它们都只能作用于一个类,如果同一个setup需要在两个类里面同时使用,那么你就要在两个测试类里面定义相同的@Before方法,然后里面写相同的代码,这就造成了代码重复。有的人说你可以用继承啊,首先我想说,我很讨厌继承这个东西,所以如果可以不用继承的话,我就不会用;再次我想说,如果你不讨厌继承的话,从现在开始,你也应该慢慢的讨厌它了。
此外,JUnit Rule还能做一些@Before这些Annotation做不到的事情,那就是他们可以动态的获取将要运行的测试类、测试方法的信息。这个在接下来的一个例子里面可以看到。

怎么用JUnit Rule?

使用框架自带的Rule

很多测试框架比如JUnit、Mockito自带给我们很多已经实现过好了的JUnit Rule,我们可以直接拿来用。比如TimeoutTemporaryFolder,等等。这些Rule的使用方法非常简单。定义一个这些类的public field,然后用@Rule修饰一下就好了。比如

public class ExampleTest {
@Rule
public Timeout timeout = new Timeout(1000); //使用Timeout这个 Rule,
@Test
public void testMethod1() throws Exception {
//your tests
} @Test
public void testMethod2() throws Exception {
//your tests2
}
//other test methods
}

那么,对于上面这个ExampleTest的每一个测试方法。它们的运行时间都不能超过1秒钟,不然就会标志为失败。而它的实现方式就是在每个方法测试之前都会记录一下时间戳,然后开始倒计时,1秒钟之后如果方法还没有运行结束,就把结果标记为失败。
这里需要注意的一点是Rule需要是public field

实现自己的Rule

当然,如果只能用框架自带的Rule,那功能未免太受限了,JUnit Rule最强大的地方在于,我们可以自己写满足我们自己需要的Rule。所以现在的问题是怎么写这个Rule。简单来说,写一个Rule就是implement一个TestRule interface,实现一个叫apply()的方法。这个方法需要返回一个Statement对象。下面给一个例子,这个 Rule的作用是,在测试方法运行之前,记录测试方法所在的类名和方法名,然后在测试方法运行之后打印出来,至于怎么在测试方法运行前后做这些事情,下面例子中的注释里面说的很清楚。

public class MethodNameExample implements TestRule {
@Override
public Statement apply(final Statement base, final Description description) {
return new Statement() {
@Override
public void evaluate() throws Throwable {
//想要在测试方法运行之前做一些事情,就在base.evaluate()之前做
String className = description.getClassName();
String methodName = description.getMethodName();

base.evaluate(); //这其实就是运行测试方法

//想要在测试方法运行之后做一些事情,就在base.evaluate()之后做
System.out.println("Class name: "+className +", method name: "+methodName);
}
};
}
}

这个Rule这样就算写好了,现在来试试,用这个 Rule的方法跟使用自带的Rule的用法是一样的,写一个public field,用@Rule修饰一下就好了。

public class ExampleUnitTest {
@Rule
public MethodNameExample methodNameExample = new MethodNameExample();
@Test
public void addition_isCorrect() throws Exception {
assertEquals(4, 2 + 2);
}
@Test
public void mulitiplication_isCorrect() throws Exception {
assertEquals(4, 2 * 2);
}
}

运行结果如下:

《安卓单元测试(八):Junit Rule的使用》

在右边的框框可以看到,把测试方法的方法名和所在的类名打印出来了。

上面的例子对于TestRule的实现应该说的比较清楚,但是看起来没多大用。下面给另外的一个例子,大家或许会觉得这个东西更有用一点。在安卓里面,我们经常在很多地方需要用到Context这个东西。我们的做法是将这个东西保存在一个类里面,作为静态变量存在:

public class ContextHolder {
private static Context sContext;
public static void set(Context context) {
sCOntext= context;
}
public static Context get() {
return sContext;
}
}

然后在自定义的Application#onCreate()里面调一下ContextHolder.set()将这个context初始化。

如果你的当前项目是一个library,那么你在测试环境下是没有这个Application的,Robolectric会给你造一个Application,放在RuntimeEnvironment.application里面。所以在测试环境下你可以使用这个instance来将ContextHolder初始化。在这种情况下,你就可以用一个Rule来实现这样的效果,在用到Context的测试方法运行之前将ContextHolder初始化:

public class ContextRule implements TestRule {
@Override
public Statement apply(Statement base, Description description) {
ContextHolder.set(RuntimeEnvironment.application);
return base;
}
}

这样,在运行一些用到context的测试方法之前,你就可以使用这个Rule来给Context赋值了。

其实,最常用的Rule之一就是结合@Mock之类的Annotation快速的创建mock,但是这点我想作为一篇单独的文章写一下。原因之一是因为它涉及到的东西不仅仅是Rule,还有其它的一些东西。更重要的原因是,我希望大家能知道这个东西,而不是被这篇文章淹没。请关注下一篇文章吧!

小结

JUnit Rule的介绍就到这里,应该说比较简单,却是非常有帮助。希望这篇文章能帮助到大家了解这个东西。
这篇文章的代码放在这个github repo里面。

获取最新文章或想加入安卓单元测试交流群,请关注下方公众号

《安卓单元测试(八):Junit Rule的使用》


推荐阅读
  • ScrollView嵌套Collectionview无痕衔接四向滚动,支持自定义TitleView
    本文介绍了如何实现ScrollView嵌套Collectionview无痕衔接四向滚动,并支持自定义TitleView。通过使用MainScrollView作为最底层,headView作为上部分,TitleView作为中间部分,Collectionview作为下面部分,实现了滚动效果。同时还介绍了使用runtime拦截_notifyDidScroll方法来实现滚动代理的方法。具体实现代码可以在github地址中找到。 ... [详细]
  • Android源码深入理解JNI技术的概述和应用
    本文介绍了Android源码中的JNI技术,包括概述和应用。JNI是Java Native Interface的缩写,是一种技术,可以实现Java程序调用Native语言写的函数,以及Native程序调用Java层的函数。在Android平台上,JNI充当了连接Java世界和Native世界的桥梁。本文通过分析Android源码中的相关文件和位置,深入探讨了JNI技术在Android开发中的重要性和应用场景。 ... [详细]
  • 自动轮播,反转播放的ViewPagerAdapter的使用方法和效果展示
    本文介绍了如何使用自动轮播、反转播放的ViewPagerAdapter,并展示了其效果。该ViewPagerAdapter支持无限循环、触摸暂停、切换缩放等功能。同时提供了使用GIF.gif的示例和github地址。通过LoopFragmentPagerAdapter类的getActualCount、getActualItem和getActualPagerTitle方法可以实现自定义的循环效果和标题展示。 ... [详细]
  • 本文介绍了iOS数据库Sqlite的SQL语句分类和常见约束关键字。SQL语句分为DDL、DML和DQL三种类型,其中DDL语句用于定义、删除和修改数据表,关键字包括create、drop和alter。常见约束关键字包括if not exists、if exists、primary key、autoincrement、not null和default。此外,还介绍了常见的数据库数据类型,包括integer、text和real。 ... [详细]
  • 欢乐的票圈重构之旅——RecyclerView的头尾布局增加
    项目重构的Git地址:https:github.comrazerdpFriendCircletreemain-dev项目同步更新的文集:http:www.jianshu.comno ... [详细]
  • 在Android开发中,使用Picasso库可以实现对网络图片的等比例缩放。本文介绍了使用Picasso库进行图片缩放的方法,并提供了具体的代码实现。通过获取图片的宽高,计算目标宽度和高度,并创建新图实现等比例缩放。 ... [详细]
  • SpringBoot uri统一权限管理的实现方法及步骤详解
    本文详细介绍了SpringBoot中实现uri统一权限管理的方法,包括表结构定义、自动统计URI并自动删除脏数据、程序启动加载等步骤。通过该方法可以提高系统的安全性,实现对系统任意接口的权限拦截验证。 ... [详细]
  • Java容器中的compareto方法排序原理解析
    本文从源码解析Java容器中的compareto方法的排序原理,讲解了在使用数组存储数据时的限制以及存储效率的问题。同时提到了Redis的五大数据结构和list、set等知识点,回忆了作者大学时代的Java学习经历。文章以作者做的思维导图作为目录,展示了整个讲解过程。 ... [详细]
  • JavaSE笔试题-接口、抽象类、多态等问题解答
    本文解答了JavaSE笔试题中关于接口、抽象类、多态等问题。包括Math类的取整数方法、接口是否可继承、抽象类是否可实现接口、抽象类是否可继承具体类、抽象类中是否可以有静态main方法等问题。同时介绍了面向对象的特征,以及Java中实现多态的机制。 ... [详细]
  • 后台获取视图对应的字符串
    1.帮助类后台获取视图对应的字符串publicclassViewHelper{将View输出为字符串(注:不会执行对应的ac ... [详细]
  • XML介绍与使用的概述及标签规则
    本文介绍了XML的基本概念和用途,包括XML的可扩展性和标签的自定义特性。同时还详细解释了XML标签的规则,包括标签的尖括号和合法标识符的组成,标签必须成对出现的原则以及特殊标签的使用方法。通过本文的阅读,读者可以对XML的基本知识有一个全面的了解。 ... [详细]
  • 本文详细介绍了Java中vector的使用方法和相关知识,包括vector类的功能、构造方法和使用注意事项。通过使用vector类,可以方便地实现动态数组的功能,并且可以随意插入不同类型的对象,进行查找、插入和删除操作。这篇文章对于需要频繁进行查找、插入和删除操作的情况下,使用vector类是一个很好的选择。 ... [详细]
  • Java学习笔记之面向对象编程(OOP)
    本文介绍了Java学习笔记中的面向对象编程(OOP)内容,包括OOP的三大特性(封装、继承、多态)和五大原则(单一职责原则、开放封闭原则、里式替换原则、依赖倒置原则)。通过学习OOP,可以提高代码复用性、拓展性和安全性。 ... [详细]
  • Java中包装类的设计原因以及操作方法
    本文主要介绍了Java中设计包装类的原因以及操作方法。在Java中,除了对象类型,还有八大基本类型,为了将基本类型转换成对象,Java引入了包装类。文章通过介绍包装类的定义和实现,解答了为什么需要包装类的问题,并提供了简单易用的操作方法。通过本文的学习,读者可以更好地理解和应用Java中的包装类。 ... [详细]
  • 模板引擎StringTemplate的使用方法和特点
    本文介绍了模板引擎StringTemplate的使用方法和特点,包括强制Model和View的分离、Lazy-Evaluation、Recursive enable等。同时,还介绍了StringTemplate语法中的属性和普通字符的使用方法,并提供了向模板填充属性的示例代码。 ... [详细]
author-avatar
tannn2502886701
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有