用Maven的quickstart archetype创建项目并结合JUnit5单元测试

1 引言

最近在读Bruce Eckel的书《On Java 8》[1](#1),其中第十六章《Validating》有一个用JUnit5进行单元测试的例子。作者用Gradle构建并运行单元测试。因为我对Maven比较熟悉,当即决定用Maven并结合JUnit5实现该例子的运行。

本博文展示:1)如何用Maven的archetype创建一个项目;2)如何写JUnit5的pom.xml依赖和相关配置;3)具体的一个简单的被测代码,并配上一个较详细的单元测试代码;4)如何用mvn test命令进行单元测试。通读本博文,能加深对Maven、JUnit5环境配置和运行机理的理解,为进一步深入学习奠定基础。

所用的环境如下:

名称 版本
Apache Maven 3.8.8
Java 1.8.0_281
编辑器 Notepad++ v7.9.1 (64-bit)
运行接口 Windows系统自带的cmd

之前我也写过相关的博文《基于JUnit4和JUnit5配合例子讲解JUnit的两种运行方式》,但那篇博文:1)所用的例子太简单,只包含了1个注解@Test;2)没讲解如何用Maven archetype创建项目;3)没讲mvn test。同时,我发现网上的这部分内容碎片较多,不利于重现。本博文克服了上述问题。

2 详细过程

2.1 利用maven创建一个空白项目

在cmd中执行如下命令:

bash 复制代码
mvn archetype:generate "-DgroupId=com.robert.validating" "-DartifactId=myValidating" "-DarchetypeArtifactId=maven-archetype-quickstart" "-DinteractiveMode=false"

上面命令中,-DgroupId用于指定组织名,实际上是包名称;-DartifactId用于指定项目名或模块名。

运行截图如下:

从上图可见,Maven会自动下载所需要的、本地库中所没有的依赖的jar包。上面命令运行成功后,如下图:

此时,在项目myValidating文件夹下会看到:

同时也生成了与packages对应的文件夹,它们符合Maven的约定,如下举例:

src/main/java/com/robert/validating/中生成了App.java,在src/test/java/com/robert/validating/中生成了AppTest.java。

2.2 在pom.xml中配置关于JUnit5的依赖和选项

在由Maven生成的pom.xml文件中添加如下内容:

xml 复制代码
<properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.compiler.target>1.8</maven.compiler.target>
  </properties>
  
  <dependencies>
    <dependency>
        <groupId>org.junit.jupiter</groupId>
        <artifactId>junit-jupiter-api</artifactId>
        <version>5.6.0</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.junit.jupiter</groupId>
        <artifactId>junit-jupiter-engine</artifactId>
        <version>5.6.0</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.junit.jupiter</groupId>
        <artifactId>junit-jupiter-params</artifactId>
        <version>5.6.0</version>
        <scope>test</scope>
    </dependency>
  </dependencies>
  
  <build>
    <plugins>
        <plugin>
            <artifactId>maven-surefire-plugin</artifactId>
            <version>2.22.2</version>
        </plugin>
    </plugins>
  </build>

上面每个配置项的具体含义就不在此讲解了,感兴趣的读者,请参考JUnit5的官方介绍。运行本项目时,可能本地库中没有相应的JUnit5的jar包,需确保电脑联网。若运行后,可以在本地库中看到相应的jar包下载成功,如下面截图:

其中,junit-jupiter-api中内容如下:

2.3 被测代码和基于JUnit5的单元测试代码举例

该例子代码完全选自《On Java 8》的第十六章Validating。

在文件夹src/main/java/com/robert/validating/下书写被测代码CountedList.java代码,如下:

java 复制代码
package com.robert.validating;

import java.util.*;
public class CountedList extends ArrayList<String> {
    private static int counter = 0;
    private int id = counter++;
    public CountedList() {
        System.out.println("CountedList #" + id);
    }
    public int getId() { return id; }
}

在文件夹src/test/java/com/robert/validating/下书写单元测试代码CountedListTest.java代码,如下:

java 复制代码
package com.robert.validating;

import java.util.*;
import org.junit.jupiter.api.*;
import static org.junit.jupiter.api.Assertions.*;
public class CountedListTest {
    private CountedList list;
    @BeforeAll
    static void beforeAllMsg() {
        System.out.println(">>> Starting CountedListTest");
    }

    @AfterAll
    static void afterAllMsg() {
        System.out.println(">>> Finished CountedListTest");
    }

    @BeforeEach
    public void initialize() {
        list = new CountedList();
        System.out.println("Set up for " + list.getId());
        for(int i = 0; i < 3; i++)
            list.add(Integer.toString(i));
    }

    @AfterEach
    public void cleanup() {
        System.out.println("Cleaning up " + list.getId());
    }

    @Test
    public void insert() {
        System.out.println("Running testInsert()");
        assertEquals(list.size(), 3);
        list.add(1, "Insert");
        assertEquals(list.size(), 4);
        assertEquals(list.get(1), "Insert");
    }

    @Test
    public void replace() {
        System.out.println("Running testReplace()");
        assertEquals(list.size(), 3);
        list.set(1, "Replace");
           assertEquals(list.size(), 3);
        assertEquals(list.get(1), "Replace");
    }

    // A helper method to simplify the code. As
    // long as it's not annotated with @Test, it will
    // not be automatically executed by JUnit.
    private void compare(List<String> lst, String[] strs) {
        assertArrayEquals(lst.toArray(new String[0]), strs);
    }

    @Test
    public void order() {
        System.out.println("Running testOrder()");
        compare(list, new String[] { "0", "1", "2" });
    }

    @Test
    public void remove() {
        System.out.println("Running testRemove()");
        assertEquals(list.size(), 3);
        list.remove(1);
        assertEquals(list.size(), 2);
        compare(list, new String[] { "0", "2" });
    }

    @Test
    public void addAll() {
        System.out.println("Running testAddAll()");
        list.addAll(Arrays.asList(new String[] {
        "An", "African", "Swallow"}));
        assertEquals(list.size(), 6);
        compare(list, new String[] { "0", "1", "2",
        "An", "African", "Swallow" });
    }
}

从上面单元测试代码中可以看出,其包含了多个注解,对于我们深入理解JUnit5的用法非常有帮助。具体含义,请参考相关书籍。

2.4 运行测试

针对上面例子,运行如下命令:

bash 复制代码
cd myValidating
mvn test

上面cd命令,切换到Maven生成的项目myValidating文件夹下,以让mvn test看到pom.xml文件。截图如下:


可以看到测试成功。

上面mvn test是运行所有的测试。我们也可以运行针对某个类的测试。看下面例子:

被测代码为

java 复制代码
package com.robert.validating;

public class Calculator {
    public double add(double number1, double number2) {
        return number1 + number2;
    }
}

单元测试代码为

java 复制代码
package com.robert.validating;

import static org.junit.jupiter.api.Assertions.assertEquals;

import org.junit.jupiter.api.Test;

public class CalculatorTest {

    @Test
    public void testAdd() {
        Calculator calculator = new Calculator();
        double result = calculator.add(10, 50);
        assertEquals(60, result, 0);
    }
}

运行命令:

bash 复制代码
mvn test -Dtest=CalculatorTest

截图如下:

注意,上面命令中要指定单元测试类的名称。

3 总结

本文详细介绍了如何基于Maven和JUnit5构建并运行单元测试项目,解决了网上相关内容碎片化、重现困难的问题;对mvn test命令也进行了讲解。以激起大家深入学习的兴趣。


  1. Bruce Eckel. On Java 8. 2017. ↩︎
相关推荐
ᐇ9592 小时前
Java集合框架实战:HashMap与HashSet的妙用
java·开发语言
乂爻yiyao2 小时前
设计模式思想——从单例模式说起
java·单例模式·设计模式
q***11652 小时前
SpringBoot创建动态定时任务的几种方式
java·spring boot·spring
by__csdn2 小时前
微服务与单体那些事儿
java·后端·微服务·云原生·架构
权泽谦2 小时前
Java 在机器学习中的应用:基于 DL4J 与 Weka 的完整实战案例
java·机器学习·数据挖掘
q***23922 小时前
nginx简单命令启动,关闭等
java·服务器·nginx
拾忆,想起2 小时前
Dubbo负载均衡全解析:五种策略详解与实战指南
java·运维·微服务·架构·负载均衡·dubbo·哈希算法
shayudiandian2 小时前
【Java】关键字 native
java
合作小小程序员小小店2 小时前
桌面开发,在线%幼儿教育考试管理%系统,基于eclipse,java,swing,mysql数据库
java·数据库·sql·mysql·eclipse·jdk