[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,极大地简化了环境依赖,使得开发者可以在不启动复杂外设的情况下快速运行测试用例。
核心理念:作者强调单测的价值不在于数量,而在于可维护性。通过架构层面的“瘦身”(如减少不必要的中间件耦合),可以从根源上降低单测的编写与维护成本。
最终成效:通过架构调整,项目实现了单测执行效率的质变,从“难以运行”转变为“随时随地可运行”,显著提升了研发交付的质量与速度。

浙公网安备 33010602011771号