单元测试是软件开发中必不可少的一环,但是在平常开发中往往因为项目周期紧,工作量大而被选择忽略,这样往往导致软件问题层出不穷。线上出现的不少问题其实在有单元测试的情况下就可以及时发现和处理,因此培养自己在日常开发中写单元测试的能力是很有必要的。无论是对自己的编码能力的提高,还是项目质量的提升,都是大有好处,本文将介绍 Java 单元测试框架 JUnit 5 的基础认识,和使用来编写单元测试。
添加相关依赖:
在pom.xml文件中添加 JUnit 5 相关组件
代码语言:javascript复制<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.6.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-params</artifactId>
<version>5.4.2</version>
<scope>test</scope>
</dependency>
JUnit 5 注解:
JUnit 5 的注解与 JUnit 4 有所区别,下表为常用注解
注解 | 描述 |
---|---|
@Test | 表示方法是测试方法。与JUnit4的@Test注解不同的是,这个注解没有声明任何属性,因为JUnit Jupiter中的测试扩展是基于他们自己的专用注解来操作的。除非被覆盖,否则这些方法可以继承。 |
@ParameterizedTest | 表示方法是参数化测试。除非被覆盖,否则这些方法可以继承。 |
@RepeatedTest | 表示方法是用于重复测试的测试模板。除非被覆盖,否则这些方法可以继承。 |
@DisplayName | 声明测试类或测试方法的自定义显示名称。这个注解不被继承。 |
@BeforeEach | 表示被注解的方法应在当前类的每个@Test,@RepeatedTest,@ParameterizedTest等方法之前执行; 类似于JUnit 4的@Before。除非被覆盖,否则这些方法可以继承。 |
@AfterEach | 表示被注解的方法应在当前类的每个@Test,@RepeatedTest,@ParameterizedTest等方法之后执行; 类似于JUnit 4的@After。除非被覆盖,否则这些方法可以继承。 |
@BeforeAll | 表示被注解的方法应该在当前类的所有@Test,@RepeatedTest,@ParameterizedTest等方法之前执行; 类似于JUnit 4的@BeforeClass。这样的方法可以继承(除非被隐藏或覆盖),并且必须是静态的。 |
@AfterAll | 表示被注解的方法应该在当前类的所有@Test,@RepeatedTest,@ParameterizedTest等方法之后执行; 并且必须是静态的。 |
@Tag | 在类或方法级别声明标签,用于过滤测试; 类似于TestNG中的test group或JUnit 4中的Categories。这个注释可以在类级别上继承,但不能在方法级别上继承。 |
@Disabled | 用于禁用测试类或测试方法; 类似于JUnit4的@Ignore。这个注解不能继承。 |
@ExtendWith | 用于注册自定义扩展。这个注解可以继承。 |
编写用例——基本的单元测试类和方法:
在了解了常用JUnit5 及其注解之后,我们来写一些基本的测试用例:
代码语言:javascript复制import org.junit.jupiter.api.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
class Junit5StandardTests {
private static final Logger LOGGER = LoggerFactory.getLogger(Junit5StandardTests.class);
@BeforeAll
static void beforeAll() {
LOGGER.info("call beforeAll()");
}
@BeforeEach
void beforeEach() {
LOGGER.info("call beforeEach()");
}
@Test
void succeedingTest() {
LOGGER.info("call succeedingTest()");
}
@Test
void failingTest() {
LOGGER.info("call failingTest()");
// fail("a failing test");
}
@Test
@Disabled("for demonstration purposes")
void skippedTest() {
LOGGER.info("call skippedTest()");
// not executed
}
@AfterEach
void afterEach() {
LOGGER.info("call afterEach()");
}
@AfterAll
static void afterAll() {
LOGGER.info("call afterAll()");
}
}
编写用例——参数化:
使用相同的测试代码,针对不同的测试数据,我们需要参数化。
基本用法:
代码语言:javascript复制@ParameterizedTest
@ValueSource(ints = { 1, 2, 3 })
void testWithValueSource(int argument) {
assertTrue(argument > 0 && argument < 4);
}
@MethodSource 允许您引用测试类或外部类的一个或多个工厂方法。
此类工厂方法必须返回流、可迭代、迭代器或参数数组。此外,这种工厂方法不能接受任何参数。测试类中的工厂方法必须是静态的。
示例代码如下:
代码语言:javascript复制@ParameterizedTest
@MethodSource("stringProvider")
void testWithSimpleMethodSource(String argument) {
assertNotNull(argument);
}
public static Set stringProvider() {
Random rand = new Random(47);
Set<String > intset = new HashSet<>();
for (int i = 0; i < 100; i ) {
intset.add(String.valueOf(i));
}
intset.add(null);
return intset;
}
如果测试方法声明多个参数,则需要返回一个集合或Arguments实例流。
示例代码如下:
代码语言:javascript复制@ParameterizedTest
@MethodSource("stringProvider")
void testWithSimpleMethodSource(String argument1) {
assertNotNull(argument1);
}
static Stream<String> stringProvider() {
List<String> list = new ArrayList<>();
list.add("foo");
list.add("bar");
Stream<String> stream1 = list.stream();
return stream1;
}
@CsvSource允许您将参数列表表示为以逗号分隔的值(例如,字符串文字)。
示例代码如下:
代码语言:javascript复制@ParameterizedTest
@CsvSource({"foo,1","bar, 2","'baz,qux',3"})
void testWithCsvSource(String first,int second){
assertNotNull(first);
assertNotEquals(0, second);
}
JUnit 5 测试套件:
通过JUnit5 实现测试套件的功能,需要依赖junit-platform-runner 、junit-jupiter-api和junit-jupiter-engine。
junit-platform-runner:用来执行测试用例和测试套件。
junit-jupiter-api有注解,通过@Test来写测试用例。
junit-jupiter-engine:引擎,在执行测试用例时要用到。
maven依赖如下:
代码语言:javascript复制<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.7.0</version>
</dependency>
<dependency>
<groupId>org.junit.platform</groupId>
<artifactId>junit-platform-runner</artifactId>
<version>1.7.0</version>
</dependency>
使用测试套件,示例代码如下:
代码语言:javascript复制import org.junit.platform.runner.JUnitPlatform;
import org.junit.platform.suite.api.SelectClasses;
import org.junit.platform.suite.api.SelectPackages;
import org.junit.platform.suite.api.SuiteDisplayName;
import org.junit.runner.RunWith;
@RunWith(JUnitPlatform.class)
@SelectClasses({CalcTest.class,CalcTest0326.class})
public class Testsuit {
}