在本教程中,我们将介绍如何创建基本的Spring Boot应用程序并将其从JUnit 4迁移到JUnit 5。
介绍
由于技术负担,大多数组织都面临着数字化转型的障碍。单元测试就是其中之一,JUnit是单元测试框架之一,业界主要使用JUnit版本4编写单元测试。JUnit 5进入市场已经有一段时间了,但是JUnit 5的迁移并未加速,这是由于开发人员缺乏明确的迁移途径。
在本练习中,您将学习从JUnit 4到JUnit 5的端到端迁移。先从一个基本的Spring Boot项目,我们使用JUnit 4。该项目将是一个具有依赖类的简单计算器应用程序。您将为此计算器应用程序编写一个单元测试,然后,排除JUnit 4依赖项,将JUnit 4测试类迁移到JUnit5。其中,JUnit 5与JUnit 4不向后兼容,但是JUnit团队创建了JUnit Vintage Project来支持JUnit 5之上的JUnit 4测试用例。
JUnit5提供了许多新功能,这些功能将有助于以参数化测试、动态测试和断言聚合等形式将单元测试提升到新的水平。
如果您只想查看项目而不想看具体的操作步骤,可以直接从此处下载。
https://github.com/developer-help/junit5-migration
使用测试设置JUnit 4项目
添加JUnit依赖关系
打开Eclipse编辑器,并创建一个简单的Maven项目名称,即JUnit4。有关实现方法,请参考下图。您需要单击“文件”菜单下的“新建”,选择“ Maven项目”并选择一个简单的原型。您可以将原型视为Maven生态系统下的模板。
检查版本和Spring Boot
创建项目后,转到Eclipse中的Explorer视图并打开此新创建项目的pom.xml文件。现在为spring-boot-starter-web和spring-boot-started-test,添加依赖项到POM中。您可以参考以下代码段按原样复制和粘贴。
请注意,该项目是Spring Boot的2.0.3的版本,带有用于单元测试的JUnit 4。
Note that this project is with version 2.0.3 of spring boot, it was having JUnit 4 for unit testing. Your pom will look like below<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>springbootJUnit4</groupId>
<artifactId>unit4</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>JUnit-4-applcation</name>
<url>http://maven.apache.org</url>
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-parent -->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.3.RELEASE</version>
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>JUnit</groupId>
<artifactId>JUnit</artifactId>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>33
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
</dependencies>
</project>
父POM
Spring Boot项目基于父POM继承的概念。父POM包含JUnit等帮助项目的版本依赖项。该代码段将帮助您了解为什么2.0.3使用JUnit 4。
图像的右侧是spring-boot-test的最新版本。由于向后兼容,JUnit 4依赖项仍然是较新的spring-boot-test项目的一部分。从本质上讲,这意味着如果同一项目中有现有的JUnit 4测试用例可用,则JUnit不会中断。在接下来的几个步骤中,会介绍如何完全排除JUnit 4并完全迁移到JUnit 5。
添加功能代码
你需要在项目中添加一个现在可用的代码。创建简单的Java类,其名称分别为Calculator、Multiplier、Adder和Subtractor。添加这些类后,您需要使用函数代码来丰富它们。为了更快地移动,您可以将以下代码段中的代码复制并粘贴到相应的类中,或参考顶部提供的Github链接。
在这里,您将创建一个主类和一个委托类,这对于学习mock的概念是必要的,因为mock的概念在任何商业项目中都是必不可少的,因为大多数项目在设计时都考虑了关注点分离。本练习使用Spring作为IOC容器。创建的Java类将作为bean注入并自动装配。
package springbootJUnit4.unit4;
import org.springframework.stereotype.Component;
@Component
public class Adder {
public Integer add(Integer a, Integer b) {
// TODO Auto-generated method stub
return a + b;
}
}
Java
package springbootjunit4.unit4;
import org.springframework.stereotype.Component;
@Component
public class Subtractor {
public Integer subtract(Integer a, Integer b) {
return a - b;
}
}
Java
package springbootjunit4.unit4;
import org.springframework.stereotype.Component;
@Component
public class Multiplier {
public Integer multiply(Integer a, Integer b) {
return a*b;
}
}
Java
package springbootjunit4.unit4;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class Calculator {
@Autowired
Adder adder;
@Autowired
Subtractor subtractor;
@Autowired
Multiplier multiplier;
public Integer subtract(Integer a, Integer b) {
if( a < b) {
throw new IllegalArgumentException("first argument cannot be less than second");
}
return subtractor.subtract(a, b);
}
public Integer multiplier(Integer a, Integer b) {
if(a == 0 || b == 0) {
throw new IllegalArgumentException("Input cannot be zero");
}
return multiplier(a, b);
}
public Integer add(Integer a, Integer b) {
if(a <0 || b < 0) {
throw new IllegalArgumentException("Invalid input positive integers only");
}
return adder.add(a, b);
}
}
添加测试代码
您需要创建称为CalculatorTest的测试类。为简单起见,您只需将代码片段复制并粘贴到创建的测试类中。在此类中,您将使用SpringBootTest注解@RunWith(SpringJUnit4ClassRunner.class)批注。Runwith注释是JUnit 4特定的注释,该注释提供了测试运行引擎。
带MockedBean注释的类中带注释的依赖项类(如Adder和Subtractor)。该批注将创建依赖项类的模拟实例,并将其注入JUnit运行期间的执行路径中。这是注入依赖性的最小侵入性的方法。否则,您必须在Calculator类中创建一个setter和getter或创建一个接受这些依赖关系的构造函数。这两种方法不会增加任何价值,但是会增加样板代码。MockedBean的这种策略将使代码尽可能接近生产环境,并仍支持单元测试。
在此代码片段中,使用SpringJUnit4 ClassRunner运行测试。这将使我们能够在测试类中自动关联Spring依赖关系,并在测试执行期间为此实例化应用程序上下文。JUnit有许多可用的运行程序,其中之一是Spring JUnit4 Class Runner。
通过右键单击类,以run作为JUnit测试选项在Eclipse中运行测试用例。它将与Spring JUnit4 ClassRunner一起运行。
package springbootjunit4.unit4;
import static org.junit.Assert.assertEquals;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest
public class CalculatorTest {
@MockBean
Adder adder;
@MockBean
Subtractor subtractor;
@Autowired
Calculator calculator;
@Test
public void testAddition() {
Mockito.when(adder.add(Mockito.anyInt(),Mockito.anyInt())).thenReturn(22);
Integer result = calculator.add(Integer.valueOf(10), Integer.valueOf(12));
assertEquals(Integer.valueOf(22),result);
}
@Test(expected=IllegalArgumentException.class)
public void testAdditionOneNegativeNumber() {
calculator.add(Integer.valueOf(-10), Integer.valueOf(12));
}
@Test(expected=IllegalArgumentException.class)
public void testAdditionBothNegativeNumber() {
calculator.add(Integer.valueOf(-10), Integer.valueOf(-12));
}
@Test
public void testSubstraction() {
Mockito.when(subtractor.subtract(Mockito.anyInt(),Mockito.anyInt())).thenReturn(1);
Integer result = calculator.subtract(Integer.valueOf(11), Integer.valueOf(10));
assertEquals(Integer.valueOf(1),result);
}
}
将JUnit 4迁移到JUnit 5
创建JUnit 5项目
在这一步中,您将创建一个新的JUnit 5项目。通过右键单击Unit 4项目的Project Explorer视图,可以进入上下文菜单。请参考下面的代码片段以获得更多的清晰度,并为其重新命名为sb-junit5。
添加JUnit 5依赖项
如上所述,JUnit Vintage引擎负责运行JUnit 4测试。在此步骤中,您将排除该依赖项。为了达到这个目的,可以打开sb-junit5项目的pom.xml,并将spring boot版本更改为最新的2.2.3。为了更快地执行此操作,您可以直接从代码段复制pom。此图显示了更改前后pom.xml的不同视图。
您最终的pom文件将如下所示:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.3.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>demo</artifactId>
<version>1.0-SNAPSHOT</version>
<name>demo</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<!--plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-deploy-plugin</artifactId>
<version>${maven-deploy-plugin.version}</version>
</plugin-->
</plugins>
</build>
<distributionManagement>
<snapshotRepository>
<id>nexusdeploymentrepo</id>
<url>http://localhost:9081/repository/maven-snapshots/</url>
</snapshotRepository>
<repository>
<id>nexusdeploymentrepo</id>
<url>http://localhost:9081/repository/maven-releases/</url>
</repository>
</distributionManagement>
</project>
JUnit 5引入了junit-vintage-engine来支持JUnit 4测试用例。您必须排除老式引擎的这种依赖性,以便成功使用JUnit 5。
修改测试代码
从复制的项目中打开Calculator Test,然后粘贴下面提供的代码段。这里有些事情值得注意。JUnit 5和JUnit 4的import语句不同,因为支持类具有不同的软件包。JUnit Runner类更改为Spring Extension。您必须按照JUnit 5使用ExtendWith注解而不是RunWith。
JUnit 5在此版本中取消了RunWith注释,因为它引入了Extend With的概念。这一概念适用于JUnit 5中的所有其他领域,在这些领域中,可以扩展现成的现有功能,从而使用户可以在现有内容之上构建内容,而无需重新设计轮子。例如,它为您提供了一种将来自程序包的批注组合起来以赋予新含义的机制,就像您要针对健全性与完整套件运行某些测试一样。您可以创建注释来过滤那些结合了@SanityTest等现有@Test注释的测试用例。如下所示,对声明的注释中有例外的测试方法有所变化,它使用的是新方法和lambda表达式。我们从JUnit 5中添加了新的注释DisplayName,以更加详细描述它们所做的工作,如下所示。
尽管Spring Boot的父pom已添加了Mockito的新版本,但Mockito API并未发生变化,支持开箱即用的Mockito,支持Junit5,尝试将测试类作为JUnit测试运行。
我们从JUnit 5中添加了一个新的注释Display Name,以更加详细地描述它们的工作方式,如下所示
@DisplayName(“其中一个参数的测试添加失败为负”)
package springbootJUnit4.unit4;
import static org.JUnit.jupiter.api.Assertions.assertEquals;
import static org.JUnit.jupiter.api.Assertions.assertThrows;
import org.JUnit.jupiter.api.DisplayName
import org.JUnit.jupiter.api.Test;
import org.JUnit.jupiter.api.extension.ExtendWith;
import org.mockito.Mockito;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.test.context.JUnit.jupiter.SpringExtension;
@ExtendWith(SpringExtension.class)
@SpringBootTest
public class CalculatorTest {
@MockBean
Adder adder;
@MockBean
Subtractor subtractor;
@Autowired
Calculator calculator;
@Test
@DisplayName(" Test positive integer Addition")
public void testAddition() {
Mockito.when(adder.add(Mockito.anyInt(),Mockito.anyInt())).thenReturn(22);
Integer result = calculator.add(Integer.valueOf(10), Integer.valueOf(12));
assertEquals(Integer.valueOf(22),result);
}
@Test()
@DisplayName(" Test addition failure for one of the arguments are negative")
public void testAdditionOneNegativeNumber() {
assertThrows(IllegalArgumentException.class,
() -> calculator.add(Integer.valueOf(-10), Integer.valueOf(12)));
}
@Test()
@DisplayName(" Test addition failure when both the arguments are negative")
public void testAdditionBothNegativeNumber() {
assertThrows(IllegalArgumentException.class,
() -> calculator.add(Integer.valueOf(-10), Integer.valueOf(-12)));
}
@Test
@DisplayName(" Test positive case for substraction")
public void testSubstraction() {
Mockito.when(subtractor.
Integer result = calculator.subtract(
assertEquals(Integer.valueOf(1),result);
}
}
Mockito API没有任何变化,尽管Spring Boot的父pom已添加了新版本的Mockito,因此无需进行任何操作即可立即支持带有Mockito的Junit5,尝试将测试类作为JUnit测试运行。这样,您就可以使用Mockito将第一组测试成功迁移到Junit5。
结论
在本练习中,您学习了如何从JUnit 4项目迁移到新的JUnit 5版本。您了解了如何在JUnit 5中使用JUnit 4确保向后兼容性。您了解了需要使用新的JUnit 5导入哪些包,了解了在JUnit 5中测试异常和使用显示名称的新方法。关于为了完全关闭JUnit 4而从Pom中排除的内容。在您的项目中,有些情况下您可能无法手动从Spring Boot的父pom继承,这些依赖项需要手动管理。在下一个练习中,我们将学习JUnit 5高级功能的用法。