java - 将 bean 注入(inject) WebMvc 测试的上下文中 : @AutoConfigureMockMvc cannot be used in combination with the @Component annotation @Configuration

标签 java spring-boot spring-test mockmvc junit-jupiter

对于我的 Java Spring 测试,我决定伪造系统时钟以使测试更容易

我有一个继承公共(public)基类的测试bean

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.MOCK)
@AutoConfigureMockMvc(print = MockMvcPrint.LOG_DEBUG)
@TestExecutionListeners(mergeMode = TestExecutionListeners.MergeMode.MERGE_WITH_DEFAULTS,
        value = {FlywayTestExecutionListener.class}
)
@FlywayTest
@Getter(AccessLevel.PROTECTED)
public abstract class AbstractMockMvcTest {}


@Configuration
@Sql(scripts = "classpath:..", executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD)
@Sql(scripts = "classpath:..", executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD)
@WithMockUser(username = "junit", authorities = {}, roles = {})
class RolesControllerTest extends AbstractMockMvcTest {

    private final Instant fixedInstant = Instant.from(OffsetDateTime.of(2021, 6, 2, 15, 54, 0, 0, ZoneOffset.ofHours(2)));

    @Bean
    Clock fakeClock() {
        return Clock.fixed(fixedInstant, ZoneId.ofOffset("UTC", ZoneOffset.ofHours(2)));
    }

}


@SpringBootApplication
public class Application {

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


    @ConditionalOnMissingBean(Clock.class)
    @Bean
    public Clock systemClock() {
        return Clock.systemUTC();
    }
}

这个想法是我的应用程序声明一个主时钟,每个需要访问时间的 bean 都使用它(例如 getClock().instant()Instant.now (getClock()))。通过模拟时钟,我使测试变得更容易。

但我发现使用 Spring beans 比 Mockito 更自然。 Java Clock有正确模拟时钟的方法

Best practice for applications is to pass a Clock into any method that requires the current instant. A dependency injection framework is one way to achieve this:

public class MyBean {
    private Clock clock;  // dependency inject
    ...
    public void process(LocalDate eventDate) {
      if (eventDate.isBefore(LocalDate.now(clock)) {
        ...
      }
    }
  }
 

This approach allows an alternate clock, such as fixed or offset to be used during testing.

但是当我尝试运行测试时,我偶然发现了这一点

@AutoConfigureMockMvc cannot be used in combination with the @Component annotation @Configuration

在 Web MVC 测试中声明额外的主要 Bean 有什么聪明的想法吗?

最佳答案

设置静态内部@TestConfiguration定义 bean 的类:

// Remove the @Configuration annotation here
@Sql(scripts = "classpath:..", executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD)
@Sql(scripts = "classpath:..", executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD)
@WithMockUser(username = "junit", authorities = {}, roles = {})
@ContextConfiguration(classes = RolesControllerTest.TestConfiguration.class) // Add a ContextConfiguration if the test configuration isn't automatically used.
class RolesControllerTest extends AbstractMockMvcTest {

    private final Instant fixedInstant = Instant.from(OffsetDateTime.of(2021, 6, 2, 15, 54, 0, 0, ZoneOffset.ofHours(2)));

    @TestConfiguration
    public static class TestConfig {

        @Bean
        Clock fakeClock() {
            return Clock.fixed(fixedInstant, ZoneId.ofOffset("UTC", ZoneOffset.ofHours(2)));
        }
    }
}

另一种方法是声明一个@MockBean私有(private)时钟并使用mockito返回固定时刻。

关于java - 将 bean 注入(inject) WebMvc 测试的上下文中 : @AutoConfigureMockMvc cannot be used in combination with the @Component annotation @Configuration,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68593575/

相关文章:

java - 改造在onResponse方法之外返回null?

java - 如何从远程服务器为位于 apache-tomcat WEB-INF/lib 文件夹下的 jar 文件创建一个下载 url?

java - 如何在 Spring 测试中注入(inject)有关测试的任何信息?

java - @DirtyContext 的替代方案,用于在 Spring Boot 下使用内存数据库中的 H2 进行隔离 JUnit 测试

java - JVM实际上是如何读取并运行字节码的?一个巨大的 switch-case 语句?

JAVA Swing : Can't add text area to a Border Layout

java - 无法确定 : com. packt.cardatabase.domain.Owner 的类型,位于表 : car, 的列 : [org. hibernate.mapping.Column(owner)]

spring-boot - 添加依赖项后,spring-cloud-sleuth 在日志中不显示任何信息

java - spring boot + angular 2部署

spring - 如何在H2数据库中使用MySQL特有的函数?