在Maven多模块项目中进行跨模块的SpringBoot单元测试

项目结构:

lua 复制代码
demo-root(父模块,pom.xml)
├── **demo-common**          -- 通用模块(核心工具类、常量、基础配置)
├── ...
├── **demo-system**          -- 系统模块(用户/角色/权限等核心业务)
└── **demo-app**             -- 启动模块(主应用,依赖其他模块)

demo-app模块下的RootApplication.java:

java 复制代码
package org.example.app;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
@MapperScan("org.example.*.mapper")
@ComponentScan("org.example")
public class RootApplication {

    public static void main(String[] args) {
        SpringApplication.run(RootApplication.class, args);
    }

}

demo-system模块下的mapper层单元测试类:

java 复制代码
package org.example.system.mapper;

import org.example.system.domain.entity.User;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.List;

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

@SpringBootTest(classes = org.example.app.RootApplication.class) // 跨模块需指定启动类
class UserMapperTest {

    @Autowired
    private UserMapper userMapper;

    @Test
    void test() {
        List<User> users = userMapper.selectList(null);
        System.out.println(users);
    }
}

demo-system模块的pom.xml:

xml 复制代码
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>demo-root</artifactId>
        <groupId>org.example</groupId>
        <version>0.0.1-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>demo-system</artifactId>

    <properties>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.example</groupId>
            <artifactId>demo-app</artifactId>
            <version>0.0.1-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>org.example</groupId>
            <artifactId>demo-common</artifactId>
            <version>0.0.1-SNAPSHOT</version>
        </dependency>
    </dependencies>
</project>

因为User实体继承自BaseEntity,所以为了获取到完整的User,打印继承字段和非继承字段,所以需要增加lombok配置。

在实体类中添加几个注解。

java 复制代码
package org.example.system.domain.entity;

import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import org.example.common.model.BaseEntity;

@TableName("users")
@Data
@EqualsAndHashCode  // lombok注解,自动处理继承字段。已在lombok.config配置callSuper=True
@ToString   // lombok注解,自动处理继承字段。已在lombok.config配置callSuper=True
public class User extends BaseEntity {
    private String username;
}

在根目录下新建一个lombok.config文件:

bash 复制代码
# 自动为所有 @ToString 添加 callSuper=true
lombok.toString.callSuper=CALL

# 自动为所有 @EqualsAndHashCode 添加 callSuper=true
lombok.equalsAndHashCode.callSuper=CALL

demo-system模块下的service层单元测试类:

java 复制代码
package org.example.system.service;

import org.example.system.domain.entity.User;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.List;

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

@SpringBootTest(classes = org.example.app.RootApplication.class)
public class IUserServiceTest {

    @Autowired
    private IUserService userService;

    @Test
    void test() {
        List<User> list = userService.list();
        System.out.println(list);
    }
}

遇到的其他问题:在运行demo-system模块下的service层单元测试类时,demo-app模块下的启动类扫到了demo-common模块下的JWT工具类显示配置文件读取失败,使用@Value注解的字段无法读取正确的参数值。

bash 复制代码
Caused by: java.lang.IllegalArgumentException: Could not resolve placeholder 'jwt.secret' in value "${jwt.secret}"

原因分析:所有模块的配置文件都叫application.yml,在正式运行时,只会加载读取启动模块的配置文件,并且, 单元测试不会自动读取src/main/resources下的配置文件,而是优先从src/test/resources/加载。

解决方案:对多模块项目的配置文件,非启动模块的配置文件采用application-xxx.yml的命名方式,并在启动模块下的配置文件中激活,确保所有模块的配置文件都可以被正常加载读取。

application-common.yml:

yml 复制代码
jwt:
  secret: "" # 建议用Base64编码
  # JWT 的签名算法(如 HS256)要求密钥是 256 位(32 字节)。Base64 编码可以确保密钥长度正确,避免因密钥长度不足导致的安全问题。
  expiration: 86400 # Token有效期(秒),默认1天(JwtUtils 中的 expiration 单位是秒
spring:
  profiles: common

application.yml:

yml 复制代码
server:
  port: 8080
spring:
  profiles:
    include: common, system

为使单元测试正常,直接复制主配置文件到测试资源目录:src/test/resources/application.yml


总结:

在Maven多模块项目中进行跨模块的SpringBoot单元测试的几个要点。

第一,在启动类中指定组件扫描路径和mapper包路径,引入启动模块依赖,在单元测试类中指定启动类。

第二,使用实体基类需添加lombok配置。

第三,差异化命名各模块的配置文件,并在启动模块的配置文件中激活。最后复制主配置文件到测试资源目录。


补充:后为正常运行启动类,我把写了数据库连接配置的application-system.yml放到启动模块下。

相关推荐
Listen·Rain1 小时前
提示词和提示词模板
java·人工智能·spring boot
小锋java12342 小时前
Maven 4 要来了:15 年后,Java 构建工具迎来"彻底重构"
java·maven
卓怡学长3 小时前
w269基于spring boot + vue 候鸟监测数据管理系统
java·数据库·spring boot·spring·intellij-idea
孫治AllenSun3 小时前
【MDC】使用 MDC 封装一个 LogMdcUtil 工具类
java·spring boot·后端
暗冰ཏོ9 小时前
Spring Boot + Vue3 订单支付模块技术实现:支付单、回调验签、幂等处理与余额扣减
前端·spring boot·后端·vue·微信支付·支付宝支付
ACGkaka_9 小时前
Spring Boot 实战(四十一):集成 BPMN(Flowable+bpmn-js)
java·spring boot·后端
ljs6482739519 小时前
智慧商城(Smart Mall):基于 Spring Boot + Vue 3 的现代化电商平台实战
linux·vue.js·spring boot·后端
添砖java_8579 小时前
网页聊天室测试报告
java·spring boot·spring·maven
whaledown10 小时前
互联网大厂Java求职面试三轮提问详解(涵盖Spring Boot、微服务、Kafka等核心技术)
java·jvm·数据库·spring boot·微服务·面试·kafka
paopaokaka_luck21 小时前
英语单词学习系统的设计与实现(基于艾宾浩斯遗忘曲线的智能复习机制、语音朗读、多题型测试与错题自动收录、Echarts图形化分析)
vue.js·spring boot·后端·echarts