Spring Boot禁用@EnableAsync用于集成测试

24

我想在运行集成测试时禁用@EnableAsync

我尝试通过创建与我的测试包中同名的类来覆盖带有@EnableAsync注释的配置文件,但它不起作用。

在此主题中:是否可以在集成测试期间禁用Spring的@Async?

我看到:

您可以... 创建一个测试配置或仅使用SyncTaskExecutor覆盖任务执行程序

但我不明白如何操作。

有什么建议吗?谢谢

6个回答

37

您提供的链接主题确实提供了一个好的解决方案。

要为测试创建SyncTaskExecutor,请确保您实际上拥有一个用于Spring上下文的测试配置类。请参考Spring文档: https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-testing.html

在此配置类中添加一个新bean:

@Bean
@Primary
public TaskExecutor taskExecutor() {
    return new SyncTaskExecutor();
}

做到这就可以了!

注意不要在您的生产配置中创建此bean!


9
жҲ‘жңҖз»ҲеҒҡзҡ„жҳҜеңЁжҲ‘зҡ„AsyncConfigurationзұ»дёҠж·»еҠ дәҶ@Profile("!test")"гҖӮи°ўи°ўгҖӮ - psv
这将仅覆盖异步任务执行器Bean定义,如果它们具有相同的Bean名称“taskExecutor”。此处未使用“@Primary”。在覆盖Bean定义时,“@Primary”无效,但是用于当有多个具有相同限定符的Bean时。此外,覆盖仅在Spring在主Bean之后处理此Bean定义时才起作用,对于内部的“@TestConfiguration”类通常是如此。 - qtips
太棒了!我已经使用@SpringBootTest@Transactional,并在后台进行一些@Async操作,但由于线程绑定事务,我的@BeforeEach方法没有意识到数据库设置的问题。唉! - andy

8
如果在运行测试时使用了唯一的配置文件名(例如“test”),则最简单的禁用异步运行测试的方法是:使用以下内容:
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.scheduling.annotation.EnableAsync;


@Profile("!test")
@Configuration
@EnableAsync
public class AsyncConfiguration {

}

在我的情况下,我必须将以下内容添加到src/test/resources/application.yml中,以确保测试在名为“test”的配置文件下运行。
spring:
  profiles:
    active: test

比实施Awaitility或覆盖taskExecutor要简单得多的解决方案。 - Nitin Jain

1

您可以通过在测试文件夹中创建以下类来覆盖主任务执行器:

@TestConfiguration
public class TestAsyncConfig {
    // create this bean if you have a custom executor you want to overwrite
    @Bean(name = "xxxxxxx") 
    public Executor xxxxxxx() {
        return new SyncTaskExecutor();
    }

    // this will overwrite the default executor
    @Bean
    public Executor taskExecutor() { 
        return new SyncTaskExecutor();
    }
}

然后在你的集成测试注释中添加以下内容:

@ContextConfiguration(classes = TestAsyncConfig.class)

0
你可以通过定义一个新的配置文件(在你的测试的包文件夹中创建一个名为DisableAsyncConfiguration的新的java文件)来实现它,其内容如下。
@Configuration
@Profile("disable-async")
public class DisableAsyncConfiguration {

    @Bean
    Executor asyncExecutor() {
        return new SyncTaskExecutor();
    }

}

然后在你的测试类中使用它。
@SpringBootTest
@@ActiveProfiles(profiles = {"test", "disable-async"})
public class MyTestThatUsesAsyncAnnotatedBeans {
   ...
}

作为结果,使用@Async注解的方法将仅在您的测试中同步执行。
解释:https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/scheduling/annotation/EnableAsync.html

-1
我们最终使用了一个名为 yourcompany.someExecutor.async 的属性,我们将其默认设置为 true(因此它不会出现在 application.yml 中),并且在测试中,我们使用 TestPropertySource 将其设置为 false。基于该属性,我们要么初始化一个 SyncTaskExecutor,要么初始化某个异步版本(例如 ThreadPoolTaskExecutor)。
请注意,这也可以启用使用多个属性,因此很容易禁用每个属性的特定执行程序。在我们的情况下,根据上下文有几个异步执行程序。
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
@TestPropertySource(properties = {
        "yourcompany.someExecutor.async=false",
})
public class SomeIntegrationTest {
  // ... tests requiring async disabled
}

@Configuration
public class SomeConfig {
    // ...
    @Value("${yourcompany.someExecutor.async:true}")
    private boolean asyncEnabled;

    @Bean("someExecutor") // specific executor
    public Executor algoExecutor() {
        if (!asyncEnabled) {
            return new SyncTaskExecutor();
        }
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(THREAD_COUNT);
        executor.setMaxPoolSize(THREAD_COUNT);
        executor.setQueueCapacity(QUEUE_CAPACITY);
        executor.setThreadNamePrefix("Some-");
        executor.initialize();
        return executor;
    }
}

生产配置不应包含此类逻辑。 - Tyulpan Tyulpan

-2
你也可以在你的类中创建两个方法,一个带有@Async注释,另一个将拥有所有需要测试的逻辑但不包含此注释,并使第一个方法调用第二个方法。然后在你的测试中,你调用具有package-private可见性的第二个方法。
例如:
@Async
public void methodAsync() {
    this.method();
}

void method() {
   // Your business logic here!
}

1
你不应该仅为了测试而更改生产代码。 - Tyulpan Tyulpan
在我看来,你只是绕过了框架工具。可以选择返回一个 CompletableFuture 而不是 void,并在测试期间强制使用带有适当值的 CompletableFuture.completedFuture()。最终,你需要确保你的业务逻辑正常运行,而不是你正在使用的框架。 - Felipe Moraes

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接