'Spring boot disable @EnableAsync for integration tests

I would like to disable @EnableAsync when I run my integration tests.

I tried to override the configuration file which is annotated with @EnableAsync with a class with the same name in my test package but it does not work.

In this topic: Is it possible to disable Spring's @Async during integration test?

I have seen that:

You can... Create a test configuration or simply override the task executor with a SyncTaskExecutor

but I do not understand how to do.

Any advice ? Thanks



Solution 1:[1]

The topic you linked does offer a good solution.

To create a SyncTaskExecutor for tests, make sure you actually have a test configuration class for spring context. Please, refer to Spring docs for that: https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-testing.html

In this configuration class add a new bean:

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

That should do it!

Take care not to create this bean in your live config!

Solution 2:[2]

If a unique profile name is used when the tests are run (e.g. "test"), then the easiest way to disable async when running tests is with

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 {

}

In my case I had to add the following to src/test/resources/application.yml to ensure tests are run under a profile named "test"

spring:
  profiles:
    active: test

Solution 3:[3]

You can overwrite the main task executor by creating the following class in test folder:

@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();
    }
}

Then add the following to annotations on your integration test:

@ContextConfiguration(classes = TestAsyncConfig.class)

Solution 4:[4]

We ended up using a prop yourcompany.someExecutor.async that we default to true (so it does not show up in the application.yml) and in a test we set it to false using TestPropertySource. Based on that prop we either initialize a SyncTaskExecutor or some async version (e.g. ThreadPoolTaskExecutor).

Note that this also enables to use multiple props so it is easy to disable a specific executor per prop. In our case we have several async executers depending on the context.

@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;
    }
}

Solution 5:[5]

You can also create two methods in your class, one that has the @Async annotation in it, and a second one that will have all the logic that you need to test without this annotation and make the first method call the second. Then in your tests you call the second method that will have package-private visibility.

Ex:

@Async
public void methodAsync() {
    this.method();
}

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

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 Dónal
Solution 3 Oleg
Solution 4 Stuck
Solution 5 Felipe Moraes