JUnit5相关内容简介
著名的Java单元测试框架Junit4已经出来很长时间了,当时我发现JUnit5已经处于测试版,就准备写文章来介绍JUnit5.不过因为还是测试版,所以有些地方还不太完善,我也有点懒没有好好写。这几天突然想起这事了,在到官网上查看,发现就在9月10日,JUnit5的正式版终于出来了!那么我就正好把文章重新好好写写,为大家介绍这个最新的JUnit框架。
框架结构
和JUnit4相比,JUnit5的结构非常清晰,为自定义插件、IDE测试执行等扩展功能做了很好的支持。这一点从项目结构就可以看出来。
JUnitPlatform
这一组的包名是org.junit.platform,从名字就可以看到,这一组的主要功能就是作为测试框架的基础平台。这个包下的模块包含基础API、执行引擎及执行器、基本的命令行执行功能、命令行界面、Maven及Gradle的测试插件等最基本的功能。
JUnitJupiter
Jupiter是JUnit5的代号,这个包下的模块包含JUnit5的主要功能。如果我们要使用JUnit5,那么必然要包含这一组模块。
JUnitVintage
Vintage是旧版本JUnit的代号,这个包下的模块可以让我们在新的JUnit平台上运行旧的JUnit3和4的测试。
导入类库
在JUnit5还在测试阶段的时候,官方文档上还有在Maven和Gradle中集成JUnit5的例子。但是到了正式版,这一部分的内容消失了,仅仅留下两个示例项目的链接,让我们自己参考(复制粘贴)。
使用Maven
junit5-maven-consumer是官方的Maven例子。本来我准备把相关的POM配置贴到这里,但是一看Maven的配置太长了,所以还是算了。如果有需求的话请自己查看这个项目的POM配置。
使用Gradle
如果用Gradle的话,那么这个问题就简单多了。在junit5-gradle-consumer示例项目中也有比较详细的说明。
首先,Gradle默认不支持JUnit5,,所以需要启用JUnitPlatformGradle插件来支持。
buildscript{ repositories{ mavenCentral() } dependencies{ classpath'org.junit.platform:junit-platform-gradle-plugin:1.0.0' } } applyplugin:'org.junit.platform.gradle.plugin'
然后是关于这个Gradle插件的配置。默认情况下所有的引擎和标签都会被执行。如果你想选择只执行某些引擎和标签的测试,可以取消下面的注释并按照你自己的需求进行修改。当然假如你没有这些高级需求,可以把这一部分删掉。
junitPlatform{ //platformVersion'1.0.0' filters{ engines{ //include'junit-jupiter','junit-vintage' //exclude'custom-engine' } tags{ //include'fast' exclude'slow' } //includeClassNamePattern'.*Test' } //enableStandardTestTasktrue //reportsDirfile('build/test-results/junit-platform')//thisisthedefault //logManager'org.apache.logging.log4j.jul.LogManager' }
如果你只需要运行JUnit5测试,只需要导入下面两个依赖项。JUnitPlatform的依赖会自动导入。
dependencies{ testCompile("org.junit.jupiter:junit-jupiter-api:5.0.0") testRuntime("org.junit.jupiter:junit-jupiter-engine:5.0.0") }
如果你想在新平台下运行旧的JUnit3和4测试,需要导入下面的依赖项。
dependencies{ testCompile("junit:junit:4.12") testRuntime("org.junit.vintage:junit-vintage-engine:4.12.0") }
编写测试
JUnit4测试
如果前面都配置好了,现在就可以开始编写测试了。首先先来复习一下旧的JUnit4测试。
publicclassJUnit4Test{ @BeforeClass publicstaticvoidinit(){ System.out.println("BeforeClass"); } @AfterClass publicstaticvoidclean(){ System.out.println("Afterclass"); } @Before publicvoidbefore(){ System.out.println("Before"); } @After publicvoidafter(){ System.out.println("After"); } @Test publicvoidtest1(){ System.out.println("Test1"); } @Test publicvoidtest2(){ System.out.println("Test2"); } }
使用gradletest等命令执行一下,就会执行这个测试。结果类似于这样。
BeforeClass Before Test1 Test2 After Afterclass
JUnit5测试
让我们来看看等效的JUnit5测试怎么写。可以看到最明显的变化:首先几个注解被重新命名成更见名知义的名称;另外一点是测试方法不必是公有方法,这样我们可以少敲几下键盘。
publicclassJUnit5Test{ @BeforeAll staticvoidbeforeAll(){ System.out.println("BeforeAll"); } @AfterAll staticvoidafterAll(){ System.out.println("AfterAll"); } @BeforeEach voidbefore(){ System.out.println("Before"); } @AfterEach voidafter(){ System.out.println("After"); } @Test voidtest1(){ System.out.println("Test1"); } @Test voidtest2(){ System.out.println("Test2"); } }
编写断言
为了验证测试用例是否正确,我们需要编写一些断言。JUnit5自带了很多断言,可以帮助我们编写测试用例。而且这些断言都带有可以接受lambda表达式的重载版本,非常适合Java8使用。当然我个人认为断言还是AssertJ更方便一点。
importstaticorg.junit.Assert.assertTrue; importstaticorg.junit.jupiter.api.Assertions.*; publicclassAssertionDemo{ @Test voidtestAssertion(){ assertEquals(10,10); assertTrue(true); assertEquals(100,100,"两个数相等"); assertAll("数字" ,()->assertEquals("name","name") ,()->assertEquals(500,500)); assertThrows(InvalidParameterException.class ,()->{ thrownewInvalidParameterException(); } ); intresult=assertTimeout(Duration.ofSeconds(5) ,()->{ inti=0,j=0; while(i<=100){ for(;j<=100000;j++) j++; i++; } returni; }); assertEquals(100,result); } }
依赖注入
现在测试类的构造方法和测试方法都可以接受参数了。ParameterResolver接口定义了如何在运行时注入参数的方法。内置的几个可以让我们获取测试用例运行时的信息。
首先是TestInfoParameterResolver。如果方法上有TestInfo类型的实例,JUnit5框架就会自动注入该实例,这个实例的几个方法可以让我们获取测试类和测试方法的名称、显示名称、标签等信息。
publicclassDependencyInjectionDemo{ @Test @DisplayName("依赖注入") @Tag("test") voidtestDisplayName(TestInfotestInfo){ assertEquals("依赖注入",testInfo.getDisplayName()); assertEquals(Collections.singleton("test"),testInfo.getTags()); } }
还有RepetitionInfoParameterResolver等内置参数解析器,将在后面介绍。
常用注解
显示名称
我们可以为测试类和测试方法添加自定义的名称,这些名贵会由测试运行器和测试报告所显示。显示名称没有变量名那样的显示,可以是一段包含空格的长字符串,甚至还可以是Emoji表情。
@DisplayName("测试类可以指定显示名称") publicclassDisplayNameDemo{ @Test @DisplayName("测试方法也可以指定显示名称") voidtestWithLongDisplayName(){ } @Test @DisplayName("显示名称还可以包含表情��") voidtestWithDisplayNameWithEmoji(){ } }
禁用测试
@Disabled注解可以用到测试类或测试方法上,可以禁用对应的测试。
@Disabled publicclassDisabledTestDemo{ @Test //@Disabled voidtestDisabled(){ } }
重复测试
如果需要让某个测试方法运行多次,使用@RepeatedTest注解。
publicclassRepeatedTestDemo{ @RepeatedTest(10) voidtestRepeated10Times(){ } }
还可以注入一个实例RepetitionInfo,检查当前重复次数和总的重复次数。
publicclassRepeatedTestDemo{ @BeforeEach voidbeforeEach(RepetitionInfoinfo){ System.out.printf("%d-%d\n" ,info.getCurrentRepetition() ,info.getTotalRepetitions()); } @RepeatedTest(10) voidtestRepeated10Times(){ } }
附带标签
在前面介绍配置Gradle的时候就说了,在配置中可以选择过滤某些标签的测试。要在代码中给标签也很简单,直接用@Tag注解即可。
@Tag("taggedTest") publicclassTagDemo{ @Test @Tag("taggedTest1") voidtestWithTag1(){ } @Test @Tag("taggedTest2") voidtestWithTag2(){ } }
嵌套测试
有时候可能需要嵌套测试来表明某些测试之间的包含关系。嵌套测试使用@Nested注解。
@DisplayName("外层测试") publicclassNestedDemo{ @Test voidtestOuter(){ } @Nested @DisplayName("内层测试") classInnerTestDemo{ @Test voidtestInner(){ } } }
需要注意只有费静态内部类才能使用Nested注解。另外,由于Java不允许内部类有静态方法,所以也不能有@BeforeAll和@AfterAll注解。如果想要突破这个限制,需要在嵌套内部类上添加@TestInstance(Lifecycle.PER_CLASS)注解,详情参见TestInstanceLifecycle。
IDE支持
虽然现在JUnit5已经出来了。但是各种工具链的支持还没有跟上。目前只有IntellijIDEA和Eclipse4.7(Oxygen)添加了对JUnit5的支持。所以如果在正式场合的话,使用JUnit4还是更稳妥一点。
常见问题
区分不同版本间的@Test注解
就在我写这篇文章的时候,我的测试小例子就遇到了一个问题,测试通不过,显示如下的错误信息。
Failures(1): JUnitVintage:yitian.study.test.AssertionDemo:initializationError ClassSource[className='yitian.study.test.AssertionDemo',filePosition=null] =>java.lang.Exception:MethodtestAssertion()shouldbepublic
英文好的同学应该可以认出来,这个错误信息说的是测试方法必须是公开的。但是前面明明说了,JUnit5取消了这个限制,那么为什么还会出现这个错误呢?我仔细一看,发现了错误所在。可能是由于以前JUnit4用的比较多,所以IDE默认对于@Test这个注解,自动补全的是这个。
importorg.junit.Test;
这个包是JUnit4下的@Test注解。如果我们要使用JUnit5的话,需要的是以下这个@Test注解。
importorg.junit.jupiter.api.Test;
修改之后,再次运行测试,果然没有问题了。当然这里为了学习和使用,我同时引用了JUnit4的包,所以才会出现这个冲突。如果没有什么特殊需求的话,建议只导入JUnit5的jar包,防止出现混淆。当然都导入也可以,只不过你就需要小心区分,不要把JUnit4的注解写到JUnit5的测试上。最后附上我的测试小例子,有兴趣的同学可以看看。
总结
以上就是本文关于JUnit5相关内容简介的全部内容,希望对大家有所帮助。感兴趣的朋友可以继续参阅本站其他相关专题,如有不足之处,欢迎留言指出。感谢朋友们对本站的支持!