你好啊,我是大阳。
这是专栏《SpringBoot自动化单元测试教程》的第四篇文章。本文我们将讨论JUnit5的假设、测试套件和条件测试。
1. JUnit5 假设
JUnit 5假设类提供静态方法来支持基于假设的条件测试执行。假设失败会导致测试中止。
当继续执行给定的测试方法没有意义时,通常使用假设。在测试报告中,这些测试将被标记为通过。
JUnit Assumptions(假设)类有以下方法:
- Assumptions.assumeTrue()
- Assumptions.assumeFalse()
- Assumptions.assumingThat()
1.1 Assumptions.assumeTrue()
该方法验证给定假设为真,如果假设为真,则测试继续进行,否则,测试执行将中止。
它具有以下重载方法:
public static void assumeTrue(boolean assumption) throws TestAbortedException
public static void assumeTrue(boolean assumption, Supplier messageSupplier) throws TestAbortedException
public static void assumeTrue(boolean assumption, String message) throws TestAbortedException
public static void assumeTrue(BooleanSupplier assumptionSupplier) throws TestAbortedException
public static void assumeTrue(BooleanSupplier assumptionSupplier, String message) throws TestAbortedException
public static void assumeTrue(BooleanSupplier assumptionSupplier, Supplier messageSupplier) throws TestAbortedException
示例:
package cn.dayangshuo.junit5.tests;
import org.junit.jupiter.api.Assumptions;
import org.junit.jupiter.api.Test;
/**
* @author DAYANG
*/
public class AssumeTests {
@Test
void testOnDev() {
System.setProperty("ENV", "DEV");
Assumptions.assumeTrue("DEV".equals(System.getProperty("ENV")));
System.out.println("测试继续执行...");
}
/**
* 测试失败,打印出失败消息
*/
@Test
void testOnProd() {
System.setProperty("ENV", "PROD");
Assumptions.assumeTrue("DEV".equals(System.getProperty("ENV")), AssumeTests::message);
System.out.println("测试不会继续执行,不会打印此行...");
}
private static String message() {
return "测试失败...";
}
}
1.2 Assumptions.assumeFalse()
该方法验证给定假设为假,如果假设为假,则测试继续,否则,测试执行被中止。
它具有以下重载方法:
public static void assumeFalse(boolean assumption) throws TestAbortedException
public static void assumeFalse(boolean assumption, Supplier messageSupplier) throws TestAbortedException
public static void assumeFalse(boolean assumption, String message) throws TestAbortedException
public static void assumeFalse(BooleanSupplier assumptionSupplier) throws TestAbortedException
public static void assumeFalse(BooleanSupplier assumptionSupplier, String message) throws TestAbortedException
public static void assumeFalse(BooleanSupplier assumptionSupplier, Supplier messageSupplier) throws TestAbortedException
示例:
package cn.dayangshuo.junit5.tests;
import org.junit.jupiter.api.Assumptions;
import org.junit.jupiter.api.Test;
/**
* @author DAYANG
*/
public class AssumeTests {
@Test
void testOnDev() {
System.setProperty("ENV", "DEV");
Assumptions.assumeFalse("DEV".equals(System.getProperty("ENV")), AssumeTests::message);
System.out.println("测试不会继续执行,不会打印此行...");
}
/**
* 测试失败,打印出失败消息
*/
@Test
void testOnProd() {
System.setProperty("ENV", "PROD");
Assumptions.assumeFalse("DEV".equals(System.getProperty("ENV")));
System.out.println("测试继续执行...");
}
private static String message() {
return "测试失败...";
}
}
1.3 Assertions.assumingThat()
该方法执行提供的可执行文件,但前提是提供的假设有效。与其他假设方法不同,此方法不会中止测试。
如果该假设无效,则该方法不起任何作用。如果假设有效且可执行文件抛出异常,则它将被视为常规测试失败。抛出的异常将按原样重新抛出,但被掩盖为未经检查的异常。
它有以下重载方法:
public static void assumingThat(boolean assumption, Executable executable)
public static void assumingThat(BooleanSupplier assumptionSupplier, Executable executable)
示例:
@Test
void testInAllEnvironments() {
System.setProperty("ENV", "DEV");
Assumptions.assumingThat("DEV".equals(System.getProperty("ENV")),
() -> {
//仅在DEV服务器上执行这些断言和打印
//即System.setProperty("ENV", "DEV")才会执行
Assertions.assertEquals(3, Calculator.add(4, 2));
});
// 在所有环境中执行这些断言
Assertions.assertEquals(13, Calculator.add(6, 7));
}
2. JUnit5测试套件
测试套件其实就是JUnit5允许我们运行多个包或者类中的测试方法,也就是分组测试。JUnit5中使用@Suite注解来声明测试套件。
在开始分组测试之前,我们先了解几个注解:
- @Tag:测试类和方法可以通过此注解进行标记。这些标签以后可用于过滤测试发现和执行。
- @Disabled:整个测试类或单个测试方法可以通过此注解禁止测试。
我们直接来看分组测试的代码示例:
package cn.dayangshuo.junit5;
import cn.dayangshuo.junit5.assertt.AssertTest;
import cn.dayangshuo.junit5.tests.LifeCycleTests;
import org.junit.platform.suite.api.*;
/**
* @author DAYANG
*/
//将LifeCycleTests和AssertTest这两个类合并在一个分组中进行测试
@SelectClasses({LifeCycleTests.class, AssertTest.class})
//也可以直接将多个包合并一个组中测试
//@SelectPackages({"cn.dayangshuo.junit5.tests"})
//这个注解代表只测试含有DEV标签的测试类或者方法
//@IncludeTags("DEV")
@Suite
@SuiteDisplayName("测试套件,分组测试")
public class SuiteTests {
}
其中LifeCycleTests和AssertTest的代码如下,直接运行SuiteTests类,下面我们来看一下LifeCycleTests和AssertTest类中哪些方法会被执行:
package cn.dayangshuo.junit5.tests;
import cn.dayangshuo.junit5.Calculator;
import org.junit.jupiter.api.*;
/**
* @author DAYANG
*/
public class LifeCycleTests {
//执行了
@Tag("DEV")
@DisplayName("生命周期测试")
@Test
void testCalcOne() {
System.out.println("======测试1执行了=======");
Assertions.assertEquals(4, Calculator.add(2, 2));
}
//执行了,但是如果SuiteTests类有@IncludeTags("DEV")注解则不会执行
@Tag("PROD")
@Test
void testCalcThree() {
System.out.println("======测试3执行了=======");
Assertions.assertEquals(6, Calculator.add(2, 4));
}
//不会执行,因为被禁用了
@Disabled
@Test
void testCalcTwo() {
System.out.println("======测试2执行了=======");
Assertions.assertEquals(6, Calculator.add(2, 4));
}
}
package cn.dayangshuo.junit5.assertt;
import cn.dayangshuo.junit5.Calculator;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Test;
import java.util.function.Supplier;
/**
* @author DAYANG
*/
public class AssertTest {
//执行了
@Test
@Tag("DEV")
void assertTest() {
//测试通过
Assertions.assertNotEquals(3, Calculator.add(2, 2));
//测试失败
Assertions.assertNotEquals(4, Calculator.add(2, 2), "Calculator.add(2, 2) test failed");
//测试失败
Supplier messageSupplier = () -> "Calculator.add(2, 2) test failed";
Assertions.assertNotEquals(4, Calculator.add(2, 2), messageSupplier);
}
}
执行结果如图:
套件测试中更多注解如下,可以使用他们包含或者排除某些类,某些包或者某些标签:
- @SelectClasses
- @SelectPackages
- @IncludePackages
- @ExcludePackages
- @IncludeClassNamePatterns
- @ExcludeClassNamePatterns
- @IncludeTags
- @ExcludeTags
3. 条件测试
JUnit Jupiter 中的ExecutionCondition扩展 API 允许开发人员以编程方式基于特定条件启用或禁用容器或测试。这种条件的最简单示例是支持注释 的内置函数 。
如操作系统条件测试:@EnabledOnOs可以通过和@DisabledOnOs注释在特定操作系统上启用或禁用容器或测试 。
package cn.dayangshuo.junit5.tests;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.condition.DisabledOnOs;
import org.junit.jupiter.api.condition.EnabledOnOs;
import org.junit.jupiter.api.condition.OS;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @author DAYANG
*/
public class ConditionsTests {
@Test
@EnabledOnOs(OS.MAC)
void onlyOnMacOs() {
// ...
}
@TestOnMac
void testOnMac() {
// ...
}
@Test
@EnabledOnOs({ OS.LINUX, OS.MAC })
void onLinuxOrMac() {
// ...
}
@Test
@DisabledOnOs(OS.WINDOWS)
void notOnWindows() {
// ...
}
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Test
@EnabledOnOs(OS.MAC)
@interface TestOnMac {
}
}
下一篇我们将讨论JUnit5让单元测试更便利的参数化测试,并且基于参数化测试我们可以更加灵活的配置我们的参数。