junit框架相关源代码分析,网上已经有很多了,本篇不做过多相关解说,主要还是要自己多读相关源代码。本篇主要对自动化测试过程相关的测试用例,测试数据,测试结果结合junit做相关扩展说明。

如果要解读junit详细源码,请参考深入JUnit源码之RunnerJUnit之参数化测试和成组测试的使用相关系列文档,本篇只对主要类进行说明,主要相关类FrameworkMethod,Description,TestClass,BlockJUnit4ClassRunner,Suite

,BlockJUnit4ClassRunnerWithParameters,parameterized,相关关系可见如下图

  1. junit4主要类介绍

Description类主要是对被测试对象的描述,它是一个树型结构;junit中测试对象类和方法,如果Description描述的是一个类,那么它的叶子节点必不为空,如果其描述的为一个方法,则其叶子节点为空;

privatefinal ArrayList<Description> fChildren= newArrayList<Description>(); //无元素

privatefinal String fDisplayName;

privatefinal Annotation[] fAnnotations;

测试树的一般元素/Composite,用fChildren保存其子结点。如一个单元测试类的Description,子结点包括所有@test修饰的方法;而一个Suite的子结点包括几个单元测试类的Description,而单元测试类和成组测试类又可以构成更大的Composite。

FrameworkMethod是对测试方法的封装,描述了执行最终测试的方法。

TestClass是对测试类封装,他只有一个参数Class<?> cls,即被测试的执行的类。

BlockJUnit4ClassRunner类是最基本的Runner,他将传入的Class<?> cls中每个Test注解类封装成一个FrameworkMethod方法并运行。

Suite类可以运行多组不同类型的Runner,比如BlockJUnit4ClassRunner,parameterized或其他自定义Runner;具体见图

parameterized是参数化的Runner,传入的Class<?> cls必须定义一个被Parameters  注解且返回类型为Collection的静态方法,如 :

@Parameters

public static Collection usernameData()

它会先执行@Parameters方法获取集合数据,对集合中的每组数据和Class<?>cls构造一个BlockJUnit4ClassRunnerWithParameters并运行其Class<?> cls中@Test注解方法,一般Class<?> cls的@Test注解方法只有一个。

BlockJUnit4ClassRunnerWithParameters和BlockJUnit4ClassRunner功能差不多,多一个参数Object接受parameterized中集合数据,主要配合Parameterized Runner使用。

 2   junit4中过滤器Filter

BlockJUnit4ClassRunner过滤调用顺序

parameterized过滤调用顺序

   3  junit相关功能扩展设想

        BlockJUnit4ClassRunner是对类中的每个Test注解方法封装成一个FrameworkMethod并运行,比如

         

public class CalculatorTest {

@Test
    public void testAdd() {
        calculator.add(2);
        calculator.add(3);
        assertEquals(5,calculator.getResult());//第一个参数填写期待结果,第二个参数填写实际结果
       
    }

@Test
    public void testSubstract() {
        calculator.add(10);
        calculator.substract(2);
        assertEquals(8,calculator.getResult());
    }

@Test
    public void testMultiply() {
        calculator.add(2);
        calculator.multiply(3);
        assertEquals(6,calculator.getResult());
    }

}

那么testAdd,testSubstract,testMultiply方法都被封装成FrameworkMethod对象,并反射调用执行。其每个方法被设计

成一个用例,方便测试设计,其主要问题:

a.   测试数据被写在方法中,修改和查看都不方便。

b.   一个类里面一个方法只对应一组测试数据(即一个测试用例),这样有很大的代码冗余。

parameterized中的TestCase类必须有@Parameters注解方法,其运行逻辑为,先调用TestCase类@Parameters注解方法,

得到Collection数据,根据Collection和TestCase生成一组BlockJUnit4ClassRunnerWithParameters(带参数)类,对每组BlockJUnit4ClassRunnerWithParameters中TestCase@Test注解方法封装成FrameworkMethod类并运行,这样的场景一般@Test方法只有一个,即使多组数据对应到一个测试方法上组成多组用例,解决上面的b问题。例如:

@RunWith(Parameterized.class)
public class SquareTest {
    private static Calculator calculator = new Calculator();
    private int param;
    private int result;

@Parameters
    public static Collection date(){
        return Arrays.asList(new Object[][]{
            {2, 4},
            {0, 0},
            {-3, 9},
      });
    }

public SquareTest(int param, int result) {
           this.param = param;
           this.result = result;
    }
   
    @Test
    public void square() {
        calculator.square(param);
        assertEquals(result, calculator.getResult());
    }
   
}

由上可知parameterized解决了一个方法对应一组测试数据的问题,使多组数据对应到一个方法上组成多组测试用例(即上面的b问题)。虽然parameterized解决了一定程度上冗余问题,但junit在使用上依然存在可改进,除了之前的a问题(测试数据写在代码里面)外,比如一个接口测试,设计了一组测试数据(如a,b,c,d,e,f,g,h,i,g,k),其中a,b,c组合数据测试代码对应该一个方法,d,e,f,g数据的测试代码对应一个方法,h数据的测试代码单独对应一个方法,i数据测试代码对应一个方法,g,k对应一个方法,按照目前junit设计的BlockJUnit4ClassRunner和parameterized来组织用例代码,那么我需要设计3个parameterized的测试类对应3组测试数据,1个BlockJUnit4ClassRunner的测试类来对应h,i的测试数据,这样就让测试代码比较乱,我们可不可以设计一个测试类,该测试类中有5个方法来运行该组测试数据,这样一个测试类对应一个接口测试,是不是更好一点。

扩展思路,1  改写parameterized,增加Collection 数据可构造传入

2   增加注解@TestCase,其中cstype = 1,rule = {1},支持用例ID配置规则。

3   增加一个过滤器,根据FrameworkMethod中的@TestCase注解和用例ID进行过滤。

增加测试数据读取类,将测试数据构造成Collection 和TestClass  传入改写后的parameterized,对Collection中的每组用例数据,按用例ID与TestClass的所有方法进行匹配,只有@TestCase规则符合用例ID的方法才被执行。见图

在下篇中再做相关代码实现分享

浅析junit4及扩展实践的更多相关文章

  1. Junit4.x扩展:运行指定方法

    相信很多道友搞开发的一般都会用到Junit单元测试工具,不知道大家有没有遇到一个这样的问题: 有的单元测试用例有很多@Test方法,甚至有的方法会执行很长时间,只能空等执行.而实际上我们只需要运行其中 ...

  2. 百万用户时尚分享网站feed系统扩展实践

    Fashiolista是一个在线的时尚交流网站,用户可以在上面建立自己的档案,和他人分享自己的以及在浏览网页时看到的时尚物品.目前,Fashiolista的用户来自于全球100多个国家,用户达百万级, ...

  3. Mac下使用Pecl安装PHP的Swoole扩展实践

    一.背景 前段时间把Mac系统重装了,PHP的一些扩展都没了,昨天需要调试一个swoole开发的项目,发现命令行中的PHP是系统自带的,如果安装swoole扩展很不方便:需要自己手动去下载swoole ...

  4. Scala 中方法扩展实践

    前言 这个名字不知道取得是否合适,简单来说要干的事情就是给某个类型添加一些扩展方法,此场景在各种语言中都会用到,比如 C# 语言,如果我们使用一个别人写好的类库,而又想给某个类库添加一些自己封装的方法 ...

  5. redis水平扩展实践,完全配置,无需代码改动

    设计思路 思路很简单,就是基于用户ID进行分库,将用户的ID字符串按照byte逐个计算ID对应的hash原值(一个数字,取绝对值,因为原始值可能过大溢出,变成负数),然后,再用这个hash原值对库的个 ...

  6. php yaf框架扩展实践五——数据层

    从狭义角度上来理解数据层就是数据库,比较广义的理解来看数据库.远程数据.文件等都可以看做数据层.项目初期的时候一般单一的数据库就可以了,随着流量的增大就要对数据层做很多的改进,例如增加从库分散读压力, ...

  7. lombok自定义扩展实践

    lombok是一款能够在java代码编译阶段改变代码的插件.比如生成setter和getter方法,生成log类变量等,能够简化一些特定的模版式代码.本文将以实现一个基于特定注解生成日志代码的方式,简 ...

  8. Sentinel Slot扩展实践-流控熔断预警实现

    前言 前几天公司生产环境一个服务由于流量上升触发了 Sentinel 的流控机制,然后用户反馈访问慢,定位发现是 task 定时任务导致,后面 task 优化之后发布,流量恢复正常. 这是一个再正常不 ...

  9. 1.还不会部署高可用的kubernetes集群?看我手把手教你使用二进制部署v1.23.6的K8S集群实践(上)

    公众号关注「WeiyiGeek」 设为「特别关注」,每天带你玩转网络安全运维.应用开发.物联网IOT学习! 本章目录: 0x00 前言简述 0x01 环境准备 主机规划 软件版本 网络规划 0x02 ...

随机推荐

  1. [转]Socket编程中,阻塞与非阻塞的区别

    阻塞:一般的I/O操作可以在新建的流中运用.在服务器回应前它等待客户端发送一个空白的行.当会话结束时,服务器关闭流和客户端socket.如果在队列中没有请示将会出现什么情况呢?那个方法将会等待一个的到 ...

  2. fir分布式滤波的fpga实现

    此设计的结构包括:1.移位寄存器链,n阶的有n-1个寄存器. 2.第一次累加部分.由fir滤波系数对称可得到对称的寄存器相加可以减小电路规模,所以第一次累加很有必要. 3,锁存并移位部分.此部分是为了 ...

  3. Python学习流程

    这是我在过去几家公司招聘到工程师,Python入职培训的过程. 时间分为4周,全部自学,仅提供大纲.适用于Web方向: 1.Week1:读完<简明Python教程>,适应Python开发环 ...

  4. kafka ksql && docker 安装试用

    备注: 使用docker 模式进行安装   1. 准备docker 环境(需要docker-compose)      docker 的安装不需要进行多描述了,直接yum 或者源码编译也可以     ...

  5. mysql 创建用户自定义函数(转可运行)

    set global log_bin_trust_function_creators = 1; -- 开启bin_log 复制 函数创建DROP FUNCTION IF EXISTS hello; - ...

  6. android中asynctask的使用实例

    参考此blog写的非常的好http://www.cnblogs.com/devinzhang/archive/2012/02/13/2350070.html MainActivity.java imp ...

  7. compoer 全局和单个项目切换源 composer update killed

    演示地址: https://blog.csdn.net/hpugym/article/details/72588393 composer update killed https://cloud.ten ...

  8. jinja2的一些用法

    1.split用法以及乘法运算 {% set user_list=l.users.split(',') %} <tr> <td>{{ l.name }}</td> ...

  9. 你知道SOCKET吗

    要想理解socket首先得熟悉一下TCP/IP协议族, TCP/IP(Transmission Control Protocol/Internet Protocol)即传输控制协议/网间协议,定义了主 ...

  10. linux下通过sysfs操作GPIO

    linux下通过sysfs操作GPIO 在嵌入式设备中对GPIO的操作是最基本的操作.一般的做法是写一个单独驱动程序,网上大多数的例子都是这样的.其实linux下面有一个通用的GPIO操作接口,那就是 ...