spring 单元测试为 logback 添加环境变量

场景描述

spring 项目中配置了 logback 收集日志,同时使用 @SpringBootTest 做单元测试。此时就报错了,文件找不见。

ERROR in ch.qos.logback.core.rolling.RollingFileAppender[file] - Failed to create parent directories for [/home/zhu/app/logs/2022-09-07.log]
ERROR in ch.qos.logback.core.rolling.RollingFileAppender[file] - openFile(null,true) call failed. java.io.FileNotFoundException: /home/zhu/app/logs/2022-09-07.log (No such file or directory)


原因

logback-spring.xml 文件中这么写的,bosc.rec.logSavePath 指定保存日志文件,可以在 application.yml 指定。

<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="false" packagingData="true">
    <springProperty scope="context" name="LOG_HOME" source="bosc.rec.logSavePath" />
  	<!-- 中间内容省略了 -->
</configuration>
# application.yml
bosc:
  rec:
    logSavePath: ${
    
    LOG_SAVE_PATH:/home/zhu/app/logs}

当单元测试启动时先加载 logback 的配置,再执行测试 case。日志文件找不到,就会抛出上面的异常。而且使用 @Before, @BeforeAll 或者 static 方法,在内部 System.setProperty() 设置环境变量的方式也都不能解决问题。因为这些方法的执行都晚于 logback 配置的加载。


解决办法

直接上代码。

public class PropertyExtension implements BeforeAllCallback {
    
    
  @Override
  public void beforeAll(ExtensionContext context) {
    
    
    System.setProperty("LOG_SAVE_PATH", "/Users/mac/Downloads/bosc/logs");
  }
}
@ExtendWith(PropertyExtension.class)
@SpringBootTest(classes = JobManageApplication.class)
class ScenePipelineRepositoryImplTest {
    
    

  @Autowired
  ScenePipelineRepository repository;

  @Test
  public void save_ScenePipeline_succeed() {
    
    
			// 内容省略
  }

啰嗦几句

之所以抛出异常是因为使用 @SpringBootTest 做单元测试,这个注解会在执行测试 case 时会启动整个 spring 服务,所以会执行 spring 的初始化过程,加载一大堆的东西,从而包括了 logback 这玩意。

但这样使用是不合理的:

原因一:单测只测一个功能点,有必要把整个服务都启动吗?又不是做集成测试。

原因二:假如服务中有定时任务 或者 向其他服务发请求的功能,那么这个任务也会运行,这是单测不想看到的现象。

@SpringBootTest 适合做集成测试,测试成功后采用 @ignore 将测试类注解掉。

spring 三层结构,每层都有单测,每层测试的目的和方式都不一样。

曾今写过的一篇单测博客

要让团队成员都遵守一些规矩还是有些挑战的。

猜你喜欢

转载自blog.csdn.net/yy_diego/article/details/126743074