简体   繁体   English

仅使用一个 Bean 的 Spring 上下文测试

[英]Spring Context Test With Just One Bean

What's the recommended way to run a spring boot test where only the one subject under test is configured in the context.运行 spring boot 测试的推荐方法是什么,其中仅在上下文中配置了一个被测主题。

If I annotate the test with如果我用

@RunWith(SpringRunner.class)
@SpringBootTest(properties = "spring.profiles.active=test")
@ContextConfiguration(classes = MyTestBean.class)

Then it seems to work - the test passes, the context starts quickly and seems to only contain the bean that I want.然后它似乎工作 - 测试通过,上下文快速启动并且似乎只包含我想要的 bean。 However, this seems like an incorrect use of the @ContextConfiguration(classes = MyTestBean.class) annotation.但是,这似乎是对@ContextConfiguration(classes = MyTestBean.class)注释的错误使用。 If I understand correctly the class that I reference is supposed to be a Configuration class, not a regular spring service bean or component for example.如果我理解正确,我引用的类应该是Configuration类,而不是常规的 spring 服务 bean 或组件。

Is that right?那正确吗? Or is this indeed a valid way to achieve this goal?或者这确实是实现这一目标的有效方法? I know there are more complex examples like org.springframework.boot.test.autoconfigure.json.JsonTest which use @TypeExcludeFilters(JsonExcludeFilter.class) to control the context - but this seems overkill for my use case.我知道有更复杂的例子,比如org.springframework.boot.test.autoconfigure.json.JsonTest它使用@TypeExcludeFilters(JsonExcludeFilter.class)来控制上下文 - 但这对我的用例来说似乎@TypeExcludeFilters(JsonExcludeFilter.class)过分。 I just want a context with my one bean.我只想要我的一个 bean 的上下文。

Clarification澄清

I know that I can just construct the one bean I am testing as a POJO without a spring context test and remove the three annotations above.我知道我可以在没有 spring 上下文测试的情况下将我正在测试的一个 bean 构建为 POJO,并删除上面的三个注释。 But in my precise use case I am actually reliant on some of the configuration applied to the context by settings in the application-test.properties file - which is why I've made this a Spring Boot test with a profile set.但在我的精确用例中,我实际上依赖于通过application-test.properties文件中的设置应用于上下文的一些配置 - 这就是为什么我将其设为具有配置文件集的 Spring Boot 测试。 From my perspective this isn't a plain unit test of a single class in isolation of the spring context configuration - the test is reliant on certain configuration being applied (which is currently provided by the spring boot app properties).从我的角度来看,这不是孤立于 spring 上下文配置的单个类的简单单元测试 - 该测试依赖于正在应用的某些配置(当前由 spring boot 应用程序属性提供)。 I can indeed just test the components as a POJO by creating a new instance outside of a spring context, I'm using constructor injection making the providing of necessary dependencies simple but the test does rely on things like the log level (the test actually makes assertions on certain logs being produced) which requires that the log level is set correctly (which is currently being done via logging.level.com.example=DEBUG in a properties file which sets up the spring context).我确实可以通过在 spring 上下文之外创建一个新实例来将组件作为 POJO 进行测试,我使用构造函数注入使提供必要的依赖项变得简单,但测试确实依赖于日志级别之类的东西(测试实际上使正在生成的某些日志上的断言),这需要正确设置日志级别(目前正在通过logging.level.com.example=DEBUG在设置 spring 上下文的属性文件中完成)。

For starters, reading the documentation first (eg, the JavaDoc linked below in this answer) is a recommend best practice since it already answers your question.对于初学者,首先阅读文档(例如,此答案中下面链接的 JavaDoc)是推荐的最佳实践,因为它已经回答了您的问题。

If I understand correctly the class that I reference is supposed to be a Configuration class, not a regular spring service bean or component for example.如果我理解正确,我引用的类应该是Configuration类,而不是常规的 spring 服务 bean 或组件。

Is that right?那正确吗?

No, that's not completely correct.不,这并不完全正确。

Classes provided to @ContextConfiguration are typically @Configuration classes, but that is not required.提供给@ContextConfiguration的类通常是@Configuration类,但这不是必需的。

Here is an excerpt from the JavaDoc for @ContextConfiguration :以下是@ContextConfigurationJavaDoc摘录:

Annotated Classes带注释的类

The term annotated class can refer to any of the following.术语带注释的类可以指以下任何一个。

  • A class annotated with @Configuration@Configuration注释的类
  • A component (ie, a class annotated with @Component , @Service , @Repository , etc.)一个组件(即用@Component@Service@Repository等注解的@Component
  • A JSR-330 compliant class that is annotated with javax.inject annotations一个 JSR-330 兼容类,用javax.inject注释javax.inject注释
  • Any other class that contains @Bean -methods包含@Bean -methods 的任何其他类

Thus you can pass any "annotated class" to @ContextConfiguration .因此,您可以将任何“带注释的类”传递给@ContextConfiguration

Or is this indeed a valid way to achieve this goal?或者这确实是实现这一目标的有效方法?

It is in fact a valid way to achieve that goal;实际上,这是实现该目标的有效方法; however, it is also a bit unusual to load an ApplicationContext that contains a single user bean.但是,加载包含单个用户 bean 的ApplicationContext也有点不寻常。

Regards,问候,

Sam ( author of the Spring TestContext Framework ) Sam( Spring TestContext Framework 的作者

It is definitely a reasonable and normal thing to only test a single class in a unit test.在单元测试中只测试一个类,这绝对是一件合理且正常的事情。

There is no problem including just one single bean in your test context.在您的测试上下文中只包含一个 bean 是没有问题的。 Really, a @Configuration is (typically) just a collection of beans.真的, @Configuration (通常)只是一个 bean 的集合。 You could hypothetically create a @Configuration class just with MyTestBean , but that would really be unnecessary, as you can accomplish doing the same thing listing your contextual beans with @ContextConfiguration#classes .假设您可以仅使用MyTestBean创建一个@Configuration类,但这实际上是不必要的,因为您可以完成使用@ContextConfiguration#classes列出上下文 bean 的相同操作。

However, I do want to point out that for only testing a single bean in a true unit test, best practice ideally leans towards setting up the bean via the constructor and testing the class that way.但是,我确实想指出,为了仅在真正的单元测试中测试单个 bean,理想的最佳实践倾向于通过构造函数设置 bean 并以这种方式测试类。 This is a key reason why the Spring guys recommend using constructor vs. property injection.这是 Spring 人员推荐使用构造函数与属性注入的一个关键原因。 See the section entitled Constructor-based or setter-based DI of this article , Oliver Gierke's comment (ie head of Spring Data project), and google for more information.参见本文题为Constructor-based or setter-based DI 的部分Oliver Gierke 的评论(即Spring Data 项目负责人),以及google了解更多信息。 This is probably the reason you're getting a weird feeling about setting up the context for the one bean!这可能是您对为一个 bean 设置上下文感到奇怪的原因!

You can also use ApplicationContextRunner to create your context using a test configuration of your choice ( even with one bean if you like, but as other people have already mentioned for one bean it's more reasonable to use the constructor the classical way without using any spring magic ).您还可以使用ApplicationContextRunner使用您选择的测试配置来创建您的上下文(如果您愿意,甚至可以使用一个 bean,但正如其他人已经提到的那样,对于一个 bean,以经典方式使用构造函数而不使用任何 spring 魔法更合理) )。

What I like this way of testing is the fact that test run very fast since you don't load all the context.我喜欢这种测试方式的事实是,由于您没有加载所有上下文,因此测试运行速度非常快。 This method is best used when the tested bean doesn't have any Autowired dependencies otherwise it's more convenient to use @SpringBootTest .当被测试的 bean 没有任何 Autowired 依赖项时最好使用此方法,否则使用@SpringBootTest更方便。

Below is an example that illustrates the way you can use it to achieve your goal:下面是一个示例,说明您可以使用它来实现目标的方式:

class MyTest {

  @Test
  void test_configuration_should_contains_my_bean() {

    new ApplicationContextRunner()
        .withUserConfiguration(TestConfiguration.class)
        .run(context -> {
          assertThat(context.getBean(MyTestBean.class)).isNotNull();
        });
  }

  @Configuraiton
  public static class TestConfiguration {
    @Bean
    public MyTestBean myTestBean(){
        new MyTestBean();
    }
  }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM