
JUnit5支持条件注解,根据布尔值判断是否执行测试。
@EnabledIf和@DisabledIf注解用来设置自定义条件,示例:
- @Test
- @EnabledIf("customCondition")
- void enabled() {
- // ...
- }
-
- @Test
- @DisabledIf("customCondition")
- void disabled() {
- // ...
- }
-
- boolean customCondition() {
- return true;
- }
其中customCondition()方法用来返回布尔值,它可以接受一个ExtensionContext类型的参数。如果定义在测试类外部,那么需要是static方法。
JUnit5的org.junit.jupiter.api.condition包中内置了一些条件注解。
操作系统条件
@EnabledOnOs和DisabledOnOs,示例:
- @Test
- @EnabledOnOs(MAC)
- void onlyOnMacOs() {
- // ...
- }
-
- @TestOnMac
- void testOnMac() {
- // ...
- }
-
- @Test
- @EnabledOnOs({ LINUX, MAC })
- void onLinuxOrMac() {
- // ...
- }
-
- @Test
- @DisabledOnOs(WINDOWS)
- void notOnWindows() {
- // ...
- }
-
- @Target(ElementType.METHOD)
- @Retention(RetentionPolicy.RUNTIME)
- @Test
- @EnabledOnOs(MAC)
- @interface TestOnMac {
- }
JRE条件
@EnabledOnJre和@DisabledOnJre用于指定版本,@EnabledForJreRange和@DisabledForJreRange用于指定版本范围,示例:
- @Test
- @EnabledOnJre(JAVA_8)
- void onlyOnJava8() {
- // ...
- }
-
- @Test
- @EnabledOnJre({ JAVA_9, JAVA_10 })
- void onJava9Or10() {
- // ...
- }
-
- @Test
- @EnabledForJreRange(min = JAVA_9, max = JAVA_11)
- void fromJava9to11() {
- // ...
- }
-
- @Test
- @EnabledForJreRange(min = JAVA_9)
- void fromJava9toCurrentJavaFeatureNumber() {
- // ...
- }
-
- @Test
- @EnabledForJreRange(max = JAVA_11)
- void fromJava8To11() {
- // ...
- }
-
- @Test
- @DisabledOnJre(JAVA_9)
- void notOnJava9() {
- // ...
- }
-
- @Test
- @DisabledForJreRange(min = JAVA_9, max = JAVA_11)
- void notFromJava9to11() {
- // ...
- }
-
- @Test
- @DisabledForJreRange(min = JAVA_9)
- void notFromJava9toCurrentJavaFeatureNumber() {
- // ...
- }
-
- @Test
- @DisabledForJreRange(max = JAVA_11)
- void notFromJava8to11() {
- // ...
- }
JVM系统属性条件
@EnabledIfSystemProperty和@DisabledIfSystemProperty,示例:
- @Test
- @EnabledIfSystemProperty(named = "os.arch", matches = ".*64.*")
- void onlyOn64BitArchitectures() {
- // ...
- }
-
- @Test
- @DisabledIfSystemProperty(named = "ci-server", matches = "true")
- void notOnCiServer() {
- // ...
- }
环境变量条件
@EnabledIfEnvironmentVariable和@DisabledIfEnvironmentVariable,示例:
- @Test
- @EnabledIfEnvironmentVariable(named = "ENV", matches = "staging-server")
- void onlyOnStagingServer() {
- // ...
- }
-
- @Test
- @DisabledIfEnvironmentVariable(named = "ENV", matches = ".*development.*")
- void notOnDeveloperWorkstation() {
- // ...
- }
- 现在我也找了很多测试的朋友,做了一个分享技术的交流群,共享了很多我们收集的技术文档和视频教程。
- 如果你不想再体验自学时找不到资源,没人解答问题,坚持几天便放弃的感受
- 可以加入我们一起交流。而且还有很多在自动化,性能,安全,测试开发等等方面有一定建树的技术大牛
- 分享他们的经验,还会分享很多直播讲座和技术沙龙
- 可以免费学习!划重点!开源的!!!
- qq群号:110685036

嵌套测试可以帮助我们对测试结构进行分层。借助于Java嵌套类的语法,JUnit5可以通过@Nested注解,实现嵌套测试,示例:
- import static org.junit.jupiter.api.Assertions.assertEquals;
- import static org.junit.jupiter.api.Assertions.assertFalse;
- import static org.junit.jupiter.api.Assertions.assertThrows;
- import static org.junit.jupiter.api.Assertions.assertTrue;
-
- import java.util.EmptyStackException;
- import java.util.Stack;
-
- import org.junit.jupiter.api.BeforeEach;
- import org.junit.jupiter.api.DisplayName;
- import org.junit.jupiter.api.Nested;
- import org.junit.jupiter.api.Test;
-
- @DisplayName("A stack")
- class TestingAStackDemo {
-
- Stack<Object> stack;
-
- @Test
- @DisplayName("is instantiated with new Stack()")
- void isInstantiatedWithNew() {
- new Stack<>();
- }
-
- @Nested
- @DisplayName("when new")
- class WhenNew {
-
- @BeforeEach
- void createNewStack() {
- stack = new Stack<>();
- }
-
- @Test
- @DisplayName("is empty")
- void isEmpty() {
- assertTrue(stack.isEmpty());
- }
-
- @Test
- @DisplayName("throws EmptyStackException when popped")
- void throwsExceptionWhenPopped() {
- assertThrows(EmptyStackException.class, stack::pop);
- }
-
- @Test
- @DisplayName("throws EmptyStackException when peeked")
- void throwsExceptionWhenPeeked() {
- assertThrows(EmptyStackException.class, stack::peek);
- }
-
- @Nested
- @DisplayName("after pushing an element")
- class AfterPushing {
-
- String anElement = "an element";
-
- @BeforeEach
- void pushAnElement() {
- stack.push(anElement);
- }
-
- @Test
- @DisplayName("it is no longer empty")
- void isNotEmpty() {
- assertFalse(stack.isEmpty());
- }
-
- @Test
- @DisplayName("returns the element when popped and is empty")
- void returnElementWhenPopped() {
- assertEquals(anElement, stack.pop());
- assertTrue(stack.isEmpty());
- }
-
- @Test
- @DisplayName("returns the element when peeked but remains not empty")
- void returnElementWhenPeeked() {
- assertEquals(anElement, stack.peek());
- assertFalse(stack.isEmpty());
- }
- }
- }
- }
外部测试类通过@BeforeEach向内部测试类传递变量。
执行后结果:

@RepeatedTest注解能控制测试方法的重复执行次数,示例:
- import static org.junit.jupiter.api.Assertions.assertEquals;
-
- import java.util.logging.Logger;
-
- import org.junit.jupiter.api.BeforeEach;
- import org.junit.jupiter.api.DisplayName;
- import org.junit.jupiter.api.RepeatedTest;
- import org.junit.jupiter.api.RepetitionInfo;
- import org.junit.jupiter.api.TestInfo;
-
- class RepeatedTestsDemo {
-
- private Logger logger = // ...
-
- @BeforeEach
- void beforeEach(TestInfo testInfo, RepetitionInfo repetitionInfo) {
- int currentRepetition = repetitionInfo.getCurrentRepetition();
- int totalRepetitions = repetitionInfo.getTotalRepetitions();
- String methodName = testInfo.getTestMethod().get().getName();
- logger.info(String.format("About to execute repetition %d of %d for %s", //
- currentRepetition, totalRepetitions, methodName));
- }
-
- @RepeatedTest(10)
- void repeatedTest() {
- // ...
- }
-
- @RepeatedTest(5)
- void repeatedTestWithRepetitionInfo(RepetitionInfo repetitionInfo) {
- assertEquals(5, repetitionInfo.getTotalRepetitions());
- }
-
- @RepeatedTest(value = 1, name = "{displayName} {currentRepetition}/{totalRepetitions}")
- @DisplayName("Repeat!")
- void customDisplayName(TestInfo testInfo) {
- assertEquals("Repeat! 1/1", testInfo.getDisplayName());
- }
-
- @RepeatedTest(value = 1, name = RepeatedTest.LONG_DISPLAY_NAME)
- @DisplayName("Details...")
- void customDisplayNameWithLongPattern(TestInfo testInfo) {
- assertEquals("Details... :: repetition 1 of 1", testInfo.getDisplayName());
- }
-
- @RepeatedTest(value = 5, name = "Wiederholung {currentRepetition} von {totalRepetitions}")
- void repeatedTestInGerman() {
- // ...
- }
-
- }
其中name可以用来自定义重复测试的显示名字,{currentRepetition}和{totalRepetitions}是当前次数和总共次数的变量。
执行结果:
- ├─ RepeatedTestsDemo ✔
- │ ├─ repeatedTest() ✔
- │ │ ├─ repetition 1 of 10 ✔
- │ │ ├─ repetition 2 of 10 ✔
- │ │ ├─ repetition 3 of 10 ✔
- │ │ ├─ repetition 4 of 10 ✔
- │ │ ├─ repetition 5 of 10 ✔
- │ │ ├─ repetition 6 of 10 ✔
- │ │ ├─ repetition 7 of 10 ✔
- │ │ ├─ repetition 8 of 10 ✔
- │ │ ├─ repetition 9 of 10 ✔
- │ │ └─ repetition 10 of 10 ✔
- │ ├─ repeatedTestWithRepetitionInfo(RepetitionInfo) ✔
- │ │ ├─ repetition 1 of 5 ✔
- │ │ ├─ repetition 2 of 5 ✔
- │ │ ├─ repetition 3 of 5 ✔
- │ │ ├─ repetition 4 of 5 ✔
- │ │ └─ repetition 5 of 5 ✔
- │ ├─ Repeat! ✔
- │ │ └─ Repeat! 1/1 ✔
- │ ├─ Details... ✔
- │ │ └─ Details... :: repetition 1 of 1 ✔
- │ └─ repeatedTestInGerman() ✔
- │ ├─ Wiederholung 1 von 5 ✔
- │ ├─ Wiederholung 2 von 5 ✔
- │ ├─ Wiederholung 3 von 5 ✔
- │ ├─ Wiederholung 4 von 5 ✔
- │ └─ Wiederholung 5 von 5 ✔
本文分别对JUnit5的条件测试、嵌套测试、重复测试进行了介绍,它们可以使得测试更加灵活和富有层次。除了这些,JUnit5还支持另一个重要且常见的测试:参数化测试。
最后感谢每一个认真阅读我文章的人,看着粉丝一路的上涨和关注,礼尚往来总是要有的,虽然不是什么很值钱的东西,如果你用得到的话可以直接拿走!

我们学习必然是为了找到高薪的工作,下面这些面试题是来自阿里、腾讯、字节等一线互联网大厂最新的面试资料,并且有字节大佬给出了权威的解答,刷完这一套面试资料相信大家都能找到满意的工作。

