如何正确模块化应用程序配置,以使测试IT,datajpa,...不会获取用于生产的所有内容

问题描述

在我们的应用程序中,我发现集成测试收集了比我想要的更多的东西。我想知道结构化的应用程序配置的样子如何,您使用什么,这样我就可以@Import仅在生产中使用那些需要的配置。

我认为文档中的相关页面是: https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#boot-features-testing-spring-boot-applications-testing-user-configuration

...在那里强调,以合理的方式构造代码很重要,但是并没有显示太多,那是什么/意味着什么。我了解配置文件,并且可能会创建在测试中无法匹配的配置文件并手动导入,但这可能不是他们所说的那样明智。

考虑以下主要入口点:

@SpringBootApplication
public class DemoApplication {

    private final SomeService someService;

    public DemoApplication(SomeService someService) {
        this.someService = someService;
    }

    @EventListener(ApplicationReadyEvent.class)
    public void started() {
        System.out.println(someService.doIt());
    }

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class,args);
    }
}

某些服务的界面:

public interface SomeService {
    public String doIt();
}

和配置:

@Configuration
public class Config {
    @Bean
    public SomeService createSomeServiceBean() {
        return new SomeService() {
            @Override
            public String doIt() {
                return String.format("Hi! (At %s)",LocalDateTime.now());
            }
        };
    }
}

在调用时,由@SpringBootApplication注释的入口点将进行组件扫描,将发现配置并且它将起作用。进一步阅读文档,我们会发现以下句子:Test slices exclude @Configuration classes from scanning([[如果@ComponentScan确实具有basePackages和basePackagesClasses的默认值]),但是可以通过以下测试:

@SpringBootTest
class DemoApplicationTests {

    @Autowired
    private SomeService someService;

    @Test
    void contextLoads() {
        System.out.println(someService.doIt());
    }
}

很高兴发现定义的SomeService bean。还是那句话意味着仅仅由@DataJpaTest注释的测试将不会注册某些配置? Kinda对我不清楚,但似乎不可能,因为@DataJpaTest会知道如何省略哪些配置,哪些不知道。

同样,我知道如何使用配置文件/排除配置。我在问“构建应用程序的明智方法”。

如何合理构造应用程序以及如何对其进行配置,以便:

  • @SpringBootApplication带注释的入口点将为生产进行组件扫描,查找和使用配置,但是这些配置需要在测试中手动导入吗?
  • 将自动扫描某些软件包的配置,以用于开发和测试环境。

解决方法

Spring Boot Test支持提供的注释仅允许使用相关bean创建一个Spring Context,以测试应用程序的特定 slice

使用此功能不需要特定的程序包结构或命名策略。

以下是其中一些:

  • @DataJpaTest:您将获得一个带有相关bean的Spring Context,以测试您的JPA 数据库接口:EntityManagerDataSource,所有接口都扩展了JpaRepository
  • @WebMvcTest:您将获得一个带有模拟servlet环境的Spring Context,用于测试您的Web层,其中包括适用于您的以下bean:所有控制器,控制器建议,WebMvcConfigurerFilter ,等等。但不是,例如带有注释的任何内容@Service@Component
  • @SpringBootTest:这将为您提供完整的Spring Context,并尝试为您创建所有bean。您可以排除一些自动配置,例如如果您不希望自动配置启动:

示例:

@SpringBootTest(webEnvironment = RANDOM_PORT)
@TestPropertySource(properties=
  {"spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration"})
  • 还有更多的测试切片注释,您可以查看here

因此,这些注释是 smart ,它们以某种方式知道它们应该在上下文中包括哪些bean,哪些应该排除。

测试应用程序的一般方法可以是使用上述的前两个测试注释来单独验证Web和数据层。接下来,使用Mockito和普通的JUnit 5对服务类进行单元测试。最后,编写一些集成测试,使用@SpringBootTest创建整个Spring Context,以一起测试所有内容。

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...