在前面的junit4初体验中我就说过,junit参数化测试是一只小怪兽,只逼编码痛点,现在我们这里来整理一下。

看过我前面的那篇初体验的就会发现一个问题,我们的测试代码大量的重复了。在这里先贴出原来的那2篇代码:

测试源码:

  1. package test.junit4test;
  2.  
  3. import java.util.regex.Matcher;
  4. import java.util.regex.Pattern;
  5.  
  6. public final class Linkin
  7. {
  8.  
  9. /**
  10. * @创建时间: 2016年1月28日
  11. * @相关参数: @param name
  12. * @相关参数: @return
  13. * @功能描述:格式化一个Java驼峰规则的字符串成数据库规则。
  14. */
  15. public static final String underscoreName(String name)
  16. {
  17. if (name == null)
  18. {
  19. return null;
  20. }
  21. if ("".equals(name))
  22. {
  23. return "";
  24. }
  25. StringBuilder result = new StringBuilder().append(name.substring(0, 1).toLowerCase());
  26. for (int i = 1; i < name.length() - 1; i++)
  27. {
  28. String s = name.substring(i, i + 1);
  29. String slc = s.toLowerCase();
  30.  
  31. String pres = name.substring(i - 1, i);
  32. String preslc = pres.toLowerCase();
  33.  
  34. if (!s.equals(slc) && pres.equals(preslc))
  35. {
  36. result.append("_").append(slc);
  37. }
  38. else
  39. {
  40. result.append(slc);
  41. }
  42. }
  43. return result.append(name.substring(name.length() - 1, name.length()).toLowerCase()).toString();
  44. }
  45.  
  46. /**
  47. * @创建时间: 2016年1月28日
  48. * @相关参数: @param name Java对象名称
  49. * @相关参数: @return 格式化后的名称
  50. * @功能描述: 将Java对象名称(每个单词的头字母大写)按照数据库命名的习惯进行格式化
  51. * <p>
  52. * 格式化后的数据为小写字母,并且使用下划线分割命名单词。
  53. * 如果参数name为null,则返回null。
  54. * 例如:employeeInfo 经过格式化之后变为 employee_info
  55. * </p>
  56. */
  57. public static final String wordFormat4DB(String name)
  58. {
  59. if (name == null)
  60. {
  61. return null;
  62. }
  63. Pattern p = Pattern.compile("[A-Z]");
  64. Matcher m = p.matcher(name);
  65. StringBuffer sb = new StringBuffer();
  66. while (m.find())
  67. {
  68. if (m.start() != 0)
  69. {
  70. m.appendReplacement(sb, ("_" + m.group()).toLowerCase());
  71. }
  72. }
  73. return m.appendTail(sb).toString().toLowerCase();
  74. }
  75.  
  76. }

测试代码:

  1. package test.junit4test;
  2.  
  3. import static org.junit.Assert.assertEquals;
  4. import static org.junit.Assert.assertNull;
  5.  
  6. import org.junit.Before;
  7. import org.junit.Test;
  8.  
  9. public class LinkinTest
  10. {
  11. private static final String JAVANAME = "userInfo";
  12. private static final String DBNAME = "user_info";
  13. Linkin linkin = null;
  14.  
  15. @Before
  16. public void setUp()
  17. {
  18. linkin = new Linkin();
  19. }
  20.  
  21. @Test
  22. // 测试字符串正常的情况
  23. public void testUnderScoreName4Normal()
  24. {
  25. String underscoreName = linkin.underscoreName(JAVANAME);
  26. assertEquals(DBNAME, underscoreName);
  27. }
  28.  
  29. @Test
  30. // 测试字符串为null的情况
  31. public void testUnderScoreName4Null()
  32. {
  33. String underscoreName = linkin.underscoreName(null);
  34. assertNull(underscoreName);
  35. }
  36.  
  37. @Test
  38. // 测试字符串为空字符串的情况
  39. public void testUnderScoreName4Empty()
  40. {
  41. String underscoreName = linkin.underscoreName("");
  42. assertEquals("", underscoreName);
  43. }
  44.  
  45. @Test
  46. // 测试当首字母大写时的情况
  47. public void testUnderScoreName4Begin()
  48. {
  49. String underscoreName = linkin.underscoreName("UserInfo");
  50. assertEquals(DBNAME, underscoreName);
  51. }
  52.  
  53. @Test
  54. // 测试当尾字母为大写时的情况
  55. public void testUnderScoreName4End()
  56. {
  57. String underscoreName = linkin.underscoreName("userInfO");
  58. assertEquals(DBNAME, underscoreName);
  59. }
  60.  
  61. @Test
  62. // 测试多个相连字母大写时的情况
  63. public void testUnderScoreName4Together()
  64. {
  65. String underscoreName = linkin.underscoreName("userINfo");
  66. assertEquals(DBNAME, underscoreName);
  67. }
  68.  
  69. }

为了保证单元测试的严谨性,我们模拟了不同类型的字符串来测试方法的处理能力,为此我们编写大量的单元测试方法。可是这些测试方法都是大同小异:代码结构都是相同的,不同的仅仅是测试数据和期望值。有没有更好的方法将测试方法中相同

的代码结构提取出来,提高代码的重用度,减少复制粘贴代码的烦恼?在以前的 JUnit 版本上,并没有好的解决方法,而现在您可以使用 JUnit 提供的参数化测试方式应对这个问题。



参数化测试的编写稍微有点麻烦(当然这是相对于 JUnit 中其它特性而言):

1,为准备使用参数化测试的测试类指定特殊的运行器 org.junit.runners.Parameterized。

2,为测试类声明几个变量,分别用于存放期望值和测试所用数据。

3,为测试类声明一个使用注解 org.junit.runners.Parameterized.Parameters 修饰的,返回值为 java.util.Collection 的公共静态方法,并在此方法中初始化所有需要测试的参数对。

4,为测试类声明一个带有参数的公共构造函数,并在其中为第二个环节中声明的几个变量赋值。

5,编写测试方法,使用定义的变量作为参数进行测试。



我们按照这个标准,重新改造一番我们的单元测试代码:

  1. package test.junit4test;
  2.  
  3. import java.util.Arrays;
  4. import java.util.Collection;
  5.  
  6. import org.junit.Assert;
  7. import org.junit.Test;
  8. import org.junit.runner.RunWith;
  9. import org.junit.runners.Parameterized;
  10. import org.junit.runners.Parameterized.Parameters;
  11.  
  12. @RunWith(Parameterized.class)
  13. public class LinkinTest
  14. {
  15. private String expected;
  16. private String target;
  17.  
  18. @Parameters
  19. public static Collection<String[]> words()
  20. {
  21. return Arrays.asList(new String[][] { { "employee_info", "employeeInfo" }, // 测试一般的处理情况
  22. { null, null }, // 测试 null 时的处理情况
  23. { "", "" }, // 测试空字符串时的处理情况
  24. { "employee_info", "EmployeeInfo" }, // 测试当首字母大写时的情况
  25. { "employee_info_a", "employeeInfoA" }, // 测试当尾字母为大写时的情况
  26. { "employee_a_info", "employeeAInfo" }// 测试多个相连字母大写时的情况
  27. });
  28. }
  29.  
  30. /**
  31. * @创建时间: 2016年1月28日
  32. * @相关参数: @param expected 期望的测试结果,对应参数集中的第一个参数
  33. * @相关参数: @param target 测试数据,对应参数集中的第二个参数
  34. * @构造描述: 参数化测试必须的构造函数
  35. */
  36. public LinkinTest(String expected, String target)
  37. {
  38. this.expected = expected;
  39. this.target = target;
  40. }
  41.  
  42. /**
  43. * 测试将 Java 对象名称到数据库名称的转换
  44. */
  45. @Test
  46. public void wordFormat4DB()
  47. {
  48. Assert.assertEquals(expected, Linkin.wordFormat4DB(target));
  49. }
  50.  
  51. }



很明显,代码瘦身了。在静态方法 words 中,我们使用二维数组来构建测试所需要的参数列表,其中每个数组中的元素的放置顺序并没有什么要求,只要和构造函数中的顺序保持一致就可以了。现在如果再增加一种测试情况,只需要在静态方法 words 中添加相应的数组即可,不再需要复制粘贴出一个新的方法出来了。运行上面的测试,将会根据@Parameters注解修饰的方法返回一个Collection,然后进行相同次数的循环。

现在我们来逐步分析下parameters这只小怪兽在junit中的运行过程,以理解这份强大的功能:

1,首先junit调用了静态方法words,然后junit为words这个集合中的每个数组进行循环。

2,junit调用唯一的构造器,注意这个时候,如果该测试类存在多个构造器,junit就会抛出一个断言错误。



3,junit使用由该数组参数构成的一系列参数来调用构造器,然后开始一次测试。

4,重复上面的步骤,直到都运行完Collection集合中的数组元素。





junit的parameterized类是junit众多测试运行器的一个。测试运行器可以让你控制junit如何运行测试。我们可以使用别的运行器,也可以自定义自己的运行器来使用,使用RunWith就可以。下一篇我们就来整理下junit运行器。

junit参数化测试的更多相关文章

  1. junit参数化测试的使用方法

    JUnit参数化测试的五个步骤:(1)为准备使用参数化测试的测试类指定特殊的运行器 org.junit.runners.Parameterized.(2)为测试类声明几个变量,分别用于存放期望值和测试 ...

  2. 计算某天的下一天:黑盒测试之等价类划分+JUnit参数化测试

    题目要求 测试以下程序:该程序有三个输入变量month.day.year(month.day和year均为整数值,并且满足:1≤month≤12.1≤day≤31和1900≤year≤2050),分别 ...

  3. Junit参数化测试Spring应用Dubbo接口

    一.创建基础类. package com.tree.autotest; import org.junit.Before;import org.springframework.context.annot ...

  4. JUnit实战(1) - JUnit起步(Parameterized参数化测试)

    创建Java Project项目,项目名称:ch01-jumpstart Calculator.java public class Calculator { public double add(dou ...

  5. junit 单元测试 - 参数化测试

    junit4.x版本需要引入如下jar包: hamcrest-core-1.3.jar junit-4.12-beta-3.jar 新建一个计算器类,如下: package com.pt; publi ...

  6. JUnit之参数化测试、套件/成组测试的使用

    原文地址http://blog.csdn.net/yqj2065/article/details/39967065 参数化测试 正如数组替代int a0,a1,a2一样,测试加法时assertEqua ...

  7. 测试 | 单元测试工具 | JUnit | 参数化

    被测试类: package project; public class MyCalendar2 { public int getNumberOfDaysInMonth(int year, int mo ...

  8. 同时使用Junit4的@Parameterized参数化测试和Spring容器

    转载:http://www.jianshu.com/p/d191fe54915f 整合Spring容器 @SpringApplicationConfiguration(classes = Applic ...

  9. 用JUnit4进行参数化测试

    参数化测试是一个JUnit 3不具备的功能. 基本使用方法 @RunWith 当类被@RunWith注解修饰,或者类继承了一个被该注解修饰的类,JUnit将会使用这个注解所指明的运行器(runner) ...

随机推荐

  1. MySQL 基础命令

    的说法啊打发 第1章 SQL语句 mysql版本:针对mysql-5.6.36 版本 (5.7会有一些变动) 1.1 常用命令 # 查看数据库 mysql> show databases; sh ...

  2. apidoc快速生成在线文档,apidoc生成静态文件的生成规则以及原理分析

    在老大的指引下,需要将系统的json文件格式转换成apidoc的json格式,也就是json格式的重组,但是这个apidoc的生成格式是不固定的,因为apidoc有自己一套的生成规则,我需要研究一下是 ...

  3. PE文件详解(八)

    本文转载自小甲鱼PE文件详解系列教程原文传送门 当应用程序需要调用DLL中的函数时,会由系统将DLL中的函数映射到程序的虚拟内存中,dll中本身没有自己的栈,它是借用的应用程序的栈,这样当dll中出现 ...

  4. C语到C++注释转换小项目

    可将其分为下面四个状态进行讨论即可: #include<stdio.h> #include<windows.h> #define INPUTFILE "input.c ...

  5. [转载]MySQL5.6 PERFORMANCE_SCHEMA 说明

    背景: MySQL 5.5开始新增一个数据库:PERFORMANCE_SCHEMA,主要用于收集数据库服务器性能参数.并且库里表的存储引擎均为PERFORMANCE_SCHEMA,而用户是不能创建存储 ...

  6. IdentityServer Topics(1)- 启动说明

    启动 IdentityServer的启动是中间件和服务的组合来实现的. 所有配置都在你的启动类(Startup.cs)中完成. 配置服务 通过以下方式调用将IdentityServer服务添加到DI系 ...

  7. Jfinal启动源码解读

    本文对Jfinal的启动源码做解释说明. PS:Jfinal启动容器可基于Tomcat/Jetty等web容器启动,本文基于Jetty的启动方式做启动源码的解读和分析,tomcat类似. 入口  JF ...

  8. Vue 组件之 Router

    Vue 组件之 Router Vue 开发单页应用的时候,免不了使用Vue组件.在单页应用上如何进行组件切换? 结构如下图所示: 主页面包含Foo组件与Bar组件,在主页面中可以进行Foo与 Bar的 ...

  9. Uva 11729 Commando War (简单贪心)

    Uva 11729  Commando War (简单贪心) There is a war and it doesn't look very promising for your country. N ...

  10. [51nod1291]Farmer

    用单调栈的话不严格的O(n^3)可以轻松艹过去,统计的时候要差分. 可以发现,对于一个单调栈里的元素,从它进栈到出栈都会重复类似的计算..再差分一波后就可以只在出栈的时候计算一下了. 具体的话看代码吧 ...