智享教程网
白蓝主题五 · 清爽阅读
首页  > 日常经验

把单元测试集成到主框架的那些事儿

最近在公司接手一个老项目,代码改一处,其他地方总出问题。每次上线前都提心吊胆,生怕哪个隐藏 Bug 突然冒出来。后来团队决定引入单元测试,并把它真正“塞”进主框架里,而不是放在角落吃灰。折腾了一阵子,现在回过头看,这个决定确实值了。

为什么不能只写测试,而不集成

刚开始我们也只是零散地写一些测试用例,跑一下就完事。但问题来了:新同事不知道要跑测试,CI/CD 流程也不检查结果,久而久之,测试代码就成了摆设。就像你买了个闹钟,却从来不设时间——它再准也没用。

只有把单元测试变成开发流程的一部分,比如提交代码前自动跑一遍,失败就拦住,大家才会真正重视它。

怎么融入主框架?以 Spring Boot 为例

我们项目是基于 Spring Boot 的,集成 JUnit 和 Mockito 相对方便。关键是在项目结构和构建脚本里做好配置。

pom.xml 中确保有这些依赖:

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>

然后在 src/test/java 下写测试类,利用 @SpringBootTest 注解加载上下文:

@SpringBootTest
class UserServiceTest {

    @Autowired
    private UserService userService;

    @Test
    void should_return_user_by_id() {
        User user = userService.findById(1L);
        assertThat(user).isNotNull();
        assertThat(user.getId()).isEqualTo(1L);
    }
}

这样写完,测试就能访问到容器里的 Bean,和真实运行环境更贴近。

让构建过程“卡住”失败的测试

Maven 默认会在 mvn testmvn package 时执行测试,但如果想确保没人绕过去,就得在 CI 阶段加一道关。

比如在 GitHub Actions 中配置:

name: Build and Test
on: [push]
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - name: Set up JDK
        uses: actions/setup-java@v3
        with:
          java-version: '17'
      - name: Run tests
        run: mvn test
      - name: Package if tests pass
        run: mvn package

只要有一个测试失败,后续步骤就不会执行,直接提醒开发者去修。

小步快跑,别想着一步到位

一开始我们想给所有旧代码补测试,结果发现太难推进。后来换了个思路:新写的代码必须带测试,老代码改动时顺手补上一点。积少成多,一个月下来覆盖率从不到 20% 涨到了 60% 多。

就像收拾屋子,别指望一天打扫完整个家,每天擦一张桌子也行。

工具只是帮手,习惯才是关键

用了 JUnit、Mockito、Coverage 插件,甚至上了 SonarQube,但最核心的还是团队有没有把写测试当成日常动作。建议在每日站会里提一句“今天测了吗”,慢慢就成了肌肉记忆。

现在我们提交代码前,IDE 自动提示哪些分支没覆盖,顺手补两行测试已经成了条件反射。这种安全感,真不是上线后盯着日志刷新能比的。