[SpringBoot]玩转单元测试系列-最后一篇

问题

使用maven-surefire-plugin 和 testng 报错:
[ERROR] Couldn't find resource: jquery.min.js
org.apache.maven.surefire.booter.SurefireBooterForkException: There was an error in the forked process

分析

直接Google AI,给出解决方案是在pom.xml配置

   <property>
     <name>usedefaultlisteners</name>
     <value>false</value> <!-- disabling default listeners is optional -->
  </property>

玩转SpringBoot单元测试

经过之前的折腾,常年累月的实践最后发现,基础架构的复杂性,加上代码的复杂性,以及SpringBoot本身的复杂性,是指数级增长的。

走过的最长的套路:

  • 团队在相当长的时间上,Dubbo 使用了运维部门提供的Zookeeper作为注册中心,Zookeeper甚至使用了加密,这就导致本地无法在IDEA当中运行,需要一遍遍在服务器上远程DEBUG。

  • 团队在近期将 Zookeeper下掉,使用了 Dubbo + Nacos,这就一下子解决了本地服务无法启动的问题,因为Nacos直接使用Grpc协议跟服务端交互,使用账号密码就行。

  • 在之前的复杂条件下,即便借助AI,AI 也吐槽,太复杂了。

  • 在之前的复杂条件下,具体而言,就是只启动 JPA 连接数据库,屏蔽 Dubbo ,ElasticSearch 等影响应用启动速度的组件,需要刀法精准,需要写非常多的注解,要了解 Mybatis,JPA 如何启动和扫瞄,非常复杂。

  • 命令行越来越长,当项目中集成了APM组件,例如SENTRY时,还需要一堆环境变量,甚至有许多人分不清java system properties,和Linux环境变量,还有Maven复杂的各种Plugin插件变量,命令非常长。

<plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-surefire-plugin</artifactId>
        <version>3.2.5</version>
        <dependencies>
            <dependency>
                <groupId>org.apache.maven.surefire</groupId>
                <artifactId>surefire-testng</artifactId>
                <version>3.2.5</version>
            </dependency>
        </dependencies>
        <configuration>
            <properties>
                <!--https://maven.apache.org/surefire/maven-surefire-plugin/examples/testng.html-->
                <property>
                    <name>usedefaultlisteners</name>
                    <value>false</value>
                </property>
                <property>
                    <name>failIfNoSpecifiedTests</name>
                    <value>false</value>
                </property>
            </properties>
            <systemPropertyVariables>
                <system_env1>test</system_env1>
                <system_env2>PRO</system_env2>
                <APP_ID>apollo-application-example</APP_ID>
                <SENTRY_SKIP_SOURCE_UPLOAD>true</SENTRY_SKIP_SOURCE_UPLOAD>
            </systemPropertyVariables>
        </configuration>
    </plugin>

启动类,注意要和正常启动的 ApplicationBootstrap启动类相同的包下:

@SpringBootTest(classes = Application.class, webEnvironment = SpringBootTest.WebEnvironment.NONE)
@ActiveProfiles("test")
public class SimpleDaoTest extends AbstractTestNGSpringContextTests {

    @Autowired
    private SomeService someService;

    /**
     * 测试some方法
     */
    @Test
    public void testSome() {
        someService.some();
    }
}

启动命令:

mvn test -Dtest=SimpleDaoTest#testSome -Dsurefire.failIfNoSpecifiedTests=false -am -pl "所在模块"

使用 JUnit 也是一样的。

surefire.failIfNoSpecifiedTests参数是做什么的?

注意尤其是在maven多模块项目中,有些module没有单元测试代码文件会在编译时失败,因此需要 -Dsurefire.failIfNoSpecifiedTests=false 直至到SimpleDaoTest所在模块。

有IDEA的情况下,为什么需要掌握命令行?

因为在CICD环境中,有可能需要跑单元测试。另外在开发阶段,本地使用 ClaudeCode 等AI工具进行 VibeCoding 的时候可以让AI 直接执行并读取输出,省的一边在IDEA中执行,一边复制粘贴报错信息给AI,日志非常多的时候就很麻烦。

总结

这是一篇在复杂企业级项目中优化单元测试的实战经验,核心观点如下:

痛点分析:在原有的架构下,由于深度依赖加密型 ZooKeeper、特定的 RPC 框架及多种中间件,导致本地运行单测极其困难,甚至需要专门的联调环境。
关键转机:通过将注册中心和配置中心从 ZooKeeper 迁移至 Nacos,极大地简化了环境依赖,使得开发者可以在不启动复杂外设的情况下快速运行测试用例。
核心理念:作者强调单测的价值不在于数量,而在于可维护性。通过架构层面的“瘦身”(如减少不必要的中间件耦合),可以从根源上降低单测的编写与维护成本。
最终成效:通过架构调整,项目实现了单测执行效率的质变,从“难以运行”转变为“随时随地可运行”,显著提升了研发交付的质量与速度。

参考链接

posted @ 2026-02-12 17:59  一杯半盏  阅读(11)  评论(0)    收藏  举报