看过我前面的那篇初体验的就会发现一个问题,咱们的测试代码大量的重复了。在这里先贴出原来的那2篇代码:java
测试源码:数据库
package test.junit4test; import java.util.regex.Matcher; import java.util.regex.Pattern; public final class Linkin { /** * @建立时间: 2016年1月28日 * @相关参数: @param name * @相关参数: @return * @功能描述:格式化一个Java驼峰规则的字符串成数据库规则。 */ public static final String underscoreName(String name) { if (name == null) { return null; } if ("".equals(name)) { return ""; } StringBuilder result = new StringBuilder().append(name.substring(0, 1).toLowerCase()); for (int i = 1; i < name.length() - 1; i++) { String s = name.substring(i, i + 1); String slc = s.toLowerCase(); String pres = name.substring(i - 1, i); String preslc = pres.toLowerCase(); if (!s.equals(slc) && pres.equals(preslc)) { result.append("_").append(slc); } else { result.append(slc); } } return result.append(name.substring(name.length() - 1, name.length()).toLowerCase()).toString(); } /** * @建立时间: 2016年1月28日 * @相关参数: @param name Java对象名称 * @相关参数: @return 格式化后的名称 * @功能描述: 将Java对象名称(每一个单词的头字母大写)按照数据库命名的习惯进行格式化 * <p> * 格式化后的数据为小写字母,而且使用下划线分割命名单词。 * 若是参数name为null,则返回null。 * 例如:employeeInfo 通过格式化以后变为 employee_info * </p> */ public static final String wordFormat4DB(String name) { if (name == null) { return null; } Pattern p = Pattern.compile("[A-Z]"); Matcher m = p.matcher(name); StringBuffer sb = new StringBuffer(); while (m.find()) { if (m.start() != 0) { m.appendReplacement(sb, ("_" + m.group()).toLowerCase()); } } return m.appendTail(sb).toString().toLowerCase(); } }
测试代码:数组
package test.junit4test; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; import org.junit.Before; import org.junit.Test; public class LinkinTest { private static final String JAVANAME = "userInfo"; private static final String DBNAME = "user_info"; Linkin linkin = null; @Before public void setUp() { linkin = new Linkin(); } @Test // 测试字符串正常的状况 public void testUnderScoreName4Normal() { String underscoreName = linkin.underscoreName(JAVANAME); assertEquals(DBNAME, underscoreName); } @Test // 测试字符串为null的状况 public void testUnderScoreName4Null() { String underscoreName = linkin.underscoreName(null); assertNull(underscoreName); } @Test // 测试字符串为空字符串的状况 public void testUnderScoreName4Empty() { String underscoreName = linkin.underscoreName(""); assertEquals("", underscoreName); } @Test // 测试当首字母大写时的状况 public void testUnderScoreName4Begin() { String underscoreName = linkin.underscoreName("UserInfo"); assertEquals(DBNAME, underscoreName); } @Test // 测试当尾字母为大写时的状况 public void testUnderScoreName4End() { String underscoreName = linkin.underscoreName("userInfO"); assertEquals(DBNAME, underscoreName); } @Test // 测试多个相连字母大写时的状况 public void testUnderScoreName4Together() { String underscoreName = linkin.underscoreName("userINfo"); assertEquals(DBNAME, underscoreName); } }
为了保证单元测试的严谨性,咱们模拟了不一样类型的字符串来测试方法的处理能力,为此咱们编写大量的单元测试方法。但是这些测试方法都是大同小异:代码结构都是相同的,不一样的仅仅是测试数据和指望值。有没有更好的方法将测试方法中相同app
的代码结构提取出来,提升代码的重用度,减小复制粘贴代码的烦恼?在之前的 JUnit 版本上,并无好的解决方法,而如今您可使用 JUnit 提供的参数化测试方式应对这个问题。函数
2,为测试类声明几个变量,分别用于存放指望值和测试所用数据。单元测试
3,为测试类声明一个使用注解 org.junit.runners.Parameterized.Parameters 修饰的,返回值为 java.util.Collection 的公共静态方法,并在此方法中初始化全部须要测试的参数对。测试
4,为测试类声明一个带有参数的公共构造函数,并在其中为第二个环节中声明的几个变量赋值。ui
5,编写测试方法,使用定义的变量做为参数进行测试。this
package test.junit4test; import java.util.Arrays; import java.util.Collection; import org.junit.Assert; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import org.junit.runners.Parameterized.Parameters; @RunWith(Parameterized.class) public class LinkinTest { private String expected; private String target; @Parameters public static Collection<String[]> words() { return Arrays.asList(new String[][] { { "employee_info", "employeeInfo" }, // 测试通常的处理状况 { null, null }, // 测试 null 时的处理状况 { "", "" }, // 测试空字符串时的处理状况 { "employee_info", "EmployeeInfo" }, // 测试当首字母大写时的状况 { "employee_info_a", "employeeInfoA" }, // 测试当尾字母为大写时的状况 { "employee_a_info", "employeeAInfo" }// 测试多个相连字母大写时的状况 }); } /** * @建立时间: 2016年1月28日 * @相关参数: @param expected 指望的测试结果,对应参数集中的第一个参数 * @相关参数: @param target 测试数据,对应参数集中的第二个参数 * @构造描述: 参数化测试必须的构造函数 */ public LinkinTest(String expected, String target) { this.expected = expected; this.target = target; } /** * 测试将 Java 对象名称到数据库名称的转换 */ @Test public void wordFormat4DB() { Assert.assertEquals(expected, Linkin.wordFormat4DB(target)); } }
很明显,代码瘦身了。在静态方法 words 中,咱们使用二维数组来构建测试所须要的参数列表,其中每一个数组中的元素的放置顺序并无什么要求,只要和构造函数中的顺序保持一致就能够了。如今若是再增长一种测试状况,只须要在静态方法 words 中添加相应的数组便可,再也不须要复制粘贴出一个新的方法出来了。运行上面的测试,将会根据@Parameters注解修饰的方法返回一个Collection,而后进行相同次数的循环。编码
如今咱们来逐步分析下parameters这只小怪兽在junit中的运行过程,以理解这份强大的功能:
1,首先junit调用了静态方法words,而后junit为words这个集合中的每一个数组进行循环。
2,junit调用惟一的构造器,注意这个时候,若是该测试类存在多个构造器,junit就会抛出一个断言错误。
3,junit使用由该数组参数构成的一系列参数来调用构造器,而后开始一次测试。
4,重复上面的步骤,直到都运行完Collection集合中的数组元素。
junit的parameterized类是junit众多测试运行器的一个。测试运行器可让你控制junit如何运行测试。咱们可使用别的运行器,也能够自定义本身的运行器来使用,使用RunWith就能够。下一篇咱们就来整理下junit运行器。