免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 1910 | 回复: 0
打印 上一主题 下一主题

JUnit8个不常被用到的功能 [复制链接]

论坛徽章:
1
IT运维版块每日发帖之星
日期:2016-06-10 06:20:00
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2016-06-07 11:54 |只看该作者 |倒序浏览


JUnit对Java开发者来说一个在普遍使用的单元测试框架。但是,大多数使用者仅仅使用了它的一部分功能。本文介绍其中不常被用到的8个功能。比如临时目录创建及自动清理,测试失败时所有断言的执行,失控测试的强制停止等。

@Rule是JUnit4的新特性。利用@Rule注解我们可以扩展JUnit的功能,在执行case的时候加入测试者特有的操作,而不影响原有的case代码:减小了特有操作和case原逻辑的耦合。譬如说我们要重复测试某个test方法时,当然我们可以在@Test方法里面写循环。但是如果想把循环和测试逻辑分开就可以利用@Rule。

@Rule只能注解在字段中,该字段必须是public的并且类型必须实现了TestRule接口或MethodRule接口。JUnit 4.9还导入了@ClassRule注解。相对于@Rule注解来说,@ClassRule是一个类级别的注解。就像@Before与@BeforeClass的区别。下面介绍JUnit中8个不常用到但很有用的功能。

通过@Rule注解可以生成临时文件或临时文件夹

有时候程序运行时必须生成文件或文件夹,往往需要写代码。JUnit4.7以后的版本中引入了TemporaryFolder。测试可以创建文件与目录并在测试运行结束后将其删除。这对于那些与文件系统打交道而且独立运行的测试来说很有用。这个功能使测试中文件夹的生成和管理变的非常简单。只要确保生成的文件夹或文件是名字不与既有的重复就行。并且,无论测试成功与否,任何在测试过程中添加到临时目录的文件或目录都会在测试结束时删除。

下面的例子中,JUnit生成的临时目录中生成一个sample.txt的文件,并且写入「JUnit Rocks!」。然后,读取新生成文件的第一行并进行比较。为使代码简化,例子中文件处理使用了Apache Commons IO。

public class TemporaryFolderTests {
@Rule
public TemporaryFolder tempFolder = new  TemporaryFolder();
@Test
public void  fileCreatedAndWrittenSuccessfully() throws IOException {
     File file = tempFolder.newFile("sample.txt");
    FileUtils.writeStringToFile(file,  "JUnit Rocks!");
    String line =  FileUtils.readFileToString(file);
    assertThat(line, is("JUnit  Rocks!"));
}
}
测试完后(无论测试成功与否)文件和目录会被删除。


取得当前的测试方法名称


想要取得执行中的测试方法名的时候,通过@Rule注解TestName类的实例化对象可以取得。
public class TestNameTests {
@Rule
public TestName name = new TestName();
@Test
public void methodNameShouldBePrinted() {
    System.out.println("Test method name:" +  name.getMethodName());
}
}
通过getMethodName()方法可以得到当前测试方法名称。


上面例子的执行结果是:
Test method name: methodNameShouldBePrinted


在一个运行测试方法过程中收集多个错误信息


使用ErrorCollector类,可以在一个测试方法中收集多个测试错误。也就是说,一个测试方法执行中,不会在第一个确认出错后就停止执行。使用ErrorCollector可以在所有点确认完后统一报出。


下在例子中有三个点要确认,它们都用ErrorCollector来确认。
public class ErrorCollectorTests {
@Rule
public ErrorCollector collector = new  ErrorCollector();
@Test
public void statementsCollectedSuccessfully()  {
    String s = null;
    collector.checkThat ("Value should not be null", null,  is(s));
    s = "";
    collector.checkThat( "Value should have the length of 1",  s.length(), is(1));
    s = "Junit!";
    collector.checkThat( "Value should have the length of 10",  s.length(), is(10));
}
}
第一个点确认成功,后面两个点都失败的时候会报下面这样的错。
java.lang.AssertionError:Value should  have the length of 1
Expected: is <1>
but: was <0>
at  org.hamcrest.MatcherAssert...
java.lang.AssertionError:Value should  have the length of 10
Expected: is <10>
but: was <6>
at  org.hamcrest.MatcherAssert...


一个测试方法用不同的参数来反复执行


用不同的参数来测试一个方法是否正确是一个比较普遍的需求。JUnit4.0以后的版本中,通过@Parameters注解可以不重复写测试方法就能实现这一需求。


使用@Parameters注解时不能使用默认Runner来运行测试代码,必须使用Parameterized.class测试类。


通过下面的例子来说明一下。
@RunWith(Parameterized.class)
public class FibonacciNumbersTests {
@Parameterized.Parameters
public  static List data() {
    return Arrays.asList(new Object[][]{
     {0, 0}, {1, 1}, {2, 1},
     {3, 2}, {4, 3}, {5, 5},
     {6, 8}});
}
private  int value;
private  int expected;
public  FibonacciNumbersTests( int input, int expected) {
     value = input;
     this.expected = expected;
}
@Test
public  void fibonacciNumberCalc () {
     assertEquals(expected, fib(value));
}
public  static int fib(int n) {
     if (n < 2) {
         return n;
     } else {
         return fib(n - 1) + fib(n - 2);
     }
}
}
第一行指定@RunWith注解,JUnit用专门的Runner类来运行测试代码。


List的各项目中第一个是input参数,第二个是expected参数。测试方法通@Parameterized.Parameters注解,把List的各个项目做为测试类的构造函数的参数。


设定执行最长时间


通过@Test注解中的timeout属性可以使执行时间过长的测试方法强制结束掉,同时测试结果也表示为测试失败。timeout属性中设定的时间是毫秒单位的。并且可以设定整个类的执行最长时间。下面例子中设定了5秒最长执行时间。
public class LongRunningTests {
@Rule
public  Timeout globalTimeout = Timeout.seconds(5);
@Test
public  void whatWeDoInATestMethodEchoesInEternity() {
      while(true);
}
}
执行结果如下:
org.junit.runners.model.TestTimedOutException:
test  timed out after 5 seconds
at  tr.com.t2.labs.tdd.sample5.LongRunningTests…


用@Category把测试分组


JUnit 4.8以后的版本中,加入了分组测试的功能。下面例6的两个测试方法中thisTestRunsSlowly()加上了@Category注解。
public class CategorizedTests {
@Test
@Category(SlowTests.class)
public  void thisTestRunsSlowly() {
     System.out.println("Slow test  running");
}

@Test
public  void thisTestRunsFast() {
     System.out.println("Fast test  running");
}
}

SlowTests.class的定义是下面这样的。
public interface SlowTests {
}

在例7中用Categories.class的Runner来运行分组后的测试代码。指定类的Runner没有设定的话@Category注解是无效的。用@IncludeCategory注解来指定要执行的接口。这样只有指定的分组才会被执行到。
@RunWith(Categories.class)
@Categories.IncludeCategory(SlowTests.class)
@Suite.SuiteClasses(CategorizedTests.class)
public class SlowTestsTestSuite {
}


自定义测试规则


通过实现TestRule接口可以简单的实现自定义测试规则。TestRule中只定义了apply()方法。在实现apply()方法时返回一个Statement类型的返回值。Statement类是定义了evaluate()方法的抽象类。具体参照以下例子。
public class MyCustomRule implements TestRule  {
private  String label;
public  MyCustomRule(String label) {
    this.label = label;
}
@Override
public  Statement apply(final Statement base, Description description){
    return new Statement() {
       @Override
       public  void evaluate() throws Throwable {
           System.out.println(label + "  before");
           base.evaluate();
           System.out.println(label + "  after");
       }
     };
   }
}

下面例9中引入了例8的自定义规则。
public class CustomRuleTests {
@Rule
public  MyCustomRule myCustomRule = new MyCustomRule("custom");
@Test
public  void myAwesomeMethodInvokedSuccessfully() {
     System.out.println("Test worked  OK");
}
}
执行结果如下。
custom before
Test worked OK
custom after


使用RuleChain


RuleChain提供一种将多个TestRule串在一起执行的机制。这在JUnit 4.10以后的版本中可以使用。需要根据特定顺序执行多个处理的时候,用RuleChain可以提高效率。


下面例10是在例9上写的一个例子。
public class RuleChainTests {
@Rule
public  RuleChain chain = RuleChain.outerRule(
new MyCustomRule("outer")).around(new  MyCustomRule("inner")
);
@Test
public  void ruleChainWorkedOK() {
     System.out.println("Test worked  OK");
}
}
执行如下:
outer before
inner before
Test worked OK
inner after
outer after

以上内容是一位资深的码农大哥写的,不知道大家看了理解的怎样?可以在评论区发布想法交流哦。

优云软件的码农都是能文能武!来认识下作者

作者自我评价:鲍震渊是一名工作10多年的老码农。2016年前专注于CRM系统的设计与开发。

秉承devops的理念,从监控、到应用体验,到自动化持续交付,优云软件一切为了您做的更好!
将IT运维化繁为简,请访问优云官网:


您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP