如何在 Spring Boot 测试中加载仅添加命名组件的基本 Spring Application-Context?

Posted

技术标签:

【中文标题】如何在 Spring Boot 测试中加载仅添加命名组件的基本 Spring Application-Context?【英文标题】:How to Load, in Spring Boot Test, Basic Spring Application-Context Adding Only Named Components? 【发布时间】:2021-12-31 23:34:09 【问题描述】:

原创

我正在尝试在 Spring Boot (v2.3.8) 应用程序的测试中加载 基本 Spring 应用程序上下文中的仅命名 组件。更具体地说,我想在测试中加载一个 Spring 应用程序上下文,它至少配置日志记录、外部属性的加载、验证(通过 Java Validation API)和@Value-plugging 但没有 MVC、Data JPA 等. 本质上,我想通过一个带约束注释的接口(例如@NotBlank)来测试一个只使用本地文件系统的@Service(没有MVC、Data JPA或任何其他Spring Boot Test“切片” ) 并通过@Value 填充一个数据成员。

我在不同的组合子集中尝试了许多注释(以及它们的一些固有属性),但无济于事:例如@SpringBootTest@Configuration@ContextConfiguration@TestConfiguration@TypeExcludeFilters等。例如:

@Validated
public interface SomeService 
    String someMethod (@NotBlank String someParam);

...
@Service
public class SomeServiceImpl implements SomeService 

    @Value("$some.value")
    private String someValue;

    @Override
    public String someMethod(String someParam) 
        // do something with local file-system,
        // with someValue in hand, and
        // knowing someParam not blank
    

...
@SpringBootTest(classes=SomeServiceImpl.class,webEnvironment=WebEnvironment.NONE)
class SomeServiceTests 

    @Autowired
    private SomeService someService;

    @Test
    void throwConstraintViolationException_whenSomeParamNil() 
        assertThrows(
            ConstraintViolationException.class,
            ()->someService.someMethod(new String()));
    
    ...

在此示例中,@SpringBootTest 的属性 classes 加载了引用的类,但隐藏了我也在寻找的所有基础知识(日志记录、验证等)。

以下摘录来自 Craig Walls 的“Spring Boot in Action”,似乎正是我正在寻找的,但它的主要工具 (@SpringApplicationConfiguration) 现在已弃用(及其官方推荐的替换 - @SpringBootTest - 表现不一样,至少在属性 classes) 方面:

尽管@ContextConfiguration 在加载 Spring 应用方面做得很好 上下文,它不会使用完整的 Spring Boot 处理加载它... SpringApplication 不仅加载应用程序上下文,还启用日志记录,加载外部 属性(application.properties 或 application.yml),以及 Spring 的其他特性 开机。如果您使用 @ContextConfiguration,您将无法获得这些功能。要在集成测试中恢复这些功能,您可以将 @ContextConfiguration 替换为 Spring Boot 的 @SpringApplicationConfiguration:

@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes=AddressBookConfiguration.class)
public class AddressServiceTests 
...

在那里,他得到了“完整的 Spring Boot 处理”,但添加了他引用的类 (@Service)(不是他的每个 @Component@Controller@Repository域)。

如果不弃用@SpringApplicationConfiguration,今天该怎么做?

更新

我最初声明我的(不是 Craig Walls 的)示例(即 @SpringBootTest(classes=SomeServiceImpl.class,webEnvironment=WebEnvironment.NONE),虽然它加载了引用的类,但模糊了 Spring Boot 通常会使用的应用程序上下文的所有基础通过进一步的实验,我发现该陈述是不准确的,因为不是全部,而是只有一些的基础知识被掩盖了,即验证(Java的实现Validation API)。换句话说,日志记录、外部属性的加载和@Value-plugging 确实是加载/配置的​​。我想我一定是搞糊涂了,在我的所有排列/尝试中。

【问题讨论】:

【参考方案1】:

经过更多的实验,我找到了答案。我不能说这是否是最好的答案,但它很简洁,而且肯定能解决问题......

import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
import org.springframework.boot.autoconfigure.validation.ValidationAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;

// automatically configures validation (implementation of Java Validation API)
@ImportAutoConfiguration(ValidationAutoConfiguration.class)

// obscures/disables any otherwise-automatic web-environment;
// automatically configures logging, loading of external properties, and @Value-plugging;
// and, beyond that, adds to application-context only _cited_ classes/configuration-classes
@SpringBootTest(classes=SomeServiceImpl.class,webEnvironment=WebEnvironment.NONE)// full context loaded, if unqualified

public class SomeServiceTests 
...

【讨论】:

以上是关于如何在 Spring Boot 测试中加载仅添加命名组件的基本 Spring Application-Context?的主要内容,如果未能解决你的问题,请参考以下文章

使用 Spring Boot 进行测试时仅从测试/资源中加载数据

无法在 Spring Boot 测试中加载类 [pg-uuid]

IntelliJ IDEA spring boot 远程Ddbug调试

如何在没有 spring-boot 的情况下在 spring-webflux 中加载配置?

如何在 Spring Boot 中加入 SQL 表?

如何使用Spring Boot在Map中加载属性?