资讯专栏INFORMATION COLUMN

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

baoxl / 1148人阅读

摘要:这些的使用方法非常简单。它们的运行时间都不能超过秒钟,不然就会标志为失败。所以在测试环境下你可以使用这个来将初始化。

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);
    }
}

运行结果如下:

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

上面的例子对于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里面。

最后,如果你对安卓单元测试感兴趣,欢迎加入我们的交流群,因为群成员超过100人,没办法扫码加入,请关注下方公众号获取加入方法。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/12964.html

相关文章

  • 【腾讯Bugly干货分享】安卓单元测试:What, Why and How

    摘要:本期,我们邀请了蘑菇街开发工程师小创,为大家分享安卓单元测试。今天很高兴跟大家分享一下,我在安卓单元测试方面的一些经验。单元测试也是类似的道理。单元测试可以减少,尽早发现,从而减少了和的时间。我们应该最关注的是单元测试。 本文来自于腾讯bugly开发者社区,非经作者同意,请勿转载,原文地址:http://dev.qq.com/topic/57d28... Dev Club 是一个交流移...

    waruqi 评论0 收藏0
  • 安卓单元测试 - 收藏集 - 掘金

    摘要:单元测试三单元测试框架的使用掘金我们写单元测试,一般都会用到一个或多个单元测试框架,在这里,我们介绍一下这个测试框架。 Android 单元测试 (三):JUnit 单元测试框架的使用 - Android - 掘金 我们写单元测试,一般都会用到一个或多个单元测试框架,在这里,我们介绍一下JUnit4这个测试框架。这是Java界用的最广泛,也是最基础的一个框架,其他的很多框架,包括我们后...

    Sunxb 评论0 收藏0
  • ContiPerf:: 更为优雅和方便单元压力测试工具。

    摘要:概述是一个轻量级的单元测试工具,基于二次开发,使用它基于注解的方式,快速在本地进行单元压测并提供详细的报告。当和都有指定时,以执行次数多的为准。测试报告最终的测试报告位于,使用浏览器打开即可。 概述 ContiPerf 是一个轻量级的单元测试工具,基于JUnit 4二次开发,使用它基于注解的方式,快速在本地进行单元压测并提供详细的报告。 Example 1. 新建 SpringBoot...

    _Zhao 评论0 收藏0
  • Java单元测试入门

    摘要:三使用介绍通过代码创建通过注解四常用方法验证方法没有被调用验证方法被调用了次方法至少被调用次方法最多被调用次备注假如你无法给你程序写单元测试,那么意味着你的程序结构有问题,需要调整或重构。 Java单元测试入门 什么是单元测试 定义:单元测试是对软件或程序的基本(最小)组成单元的测试对象:方法、类特点:showImg(https://segmentfault.com/img/bVbcR...

    cfanr 评论0 收藏0
  • Android单元测试(七):Robolectric,在JVM上调用安卓

    摘要:当时崇拜之极,却仍然觉得写单元测试是很麻烦的一件事情。很多人甚至说离开了单元测试,他们便没有办法写代码。这些都让我对单元测试的好感度逐渐的上升。 今天讲讲Android上做单元测试的最后一个难点,那就是在JVM上无法调用安卓相关的类,不然的话,会报类似于下的错误: java.lang.RuntimeException: Method isEmpty in android.text.Te...

    whlong 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<