Reputation: 1430
In my application, I have a component that reads data from other system when the application is started. However, during testing, I don't want this component to be created
@Component
@Slf4j
public class DeviceStatisticsSyncHandler {
@EventListener
public void handle(ApplicationReadyEvent event) {
syncDeviceStatisticsDataSync();
}
@Value("${test.mode:false}")
public boolean serviceEnabled;
}
I can use condition to solve this, but other code readers need to understand, so I don't think this is a very good method:
@EventListener(condition = "@deviceStatisticsSyncHandler .isServiceEnabled()")
public void handle(ApplicationReadyEvent event) {
syncDeviceStatisticsDataSync();
}
public boolean isServiceEnabled() {
return !serviceEnabled;
}
@Value("${test.mode:false}")
public boolean serviceEnabled;
My application doesn't use Profiles, is there any other method to solve this problem.
Spring Boot version:2.1.3
Upvotes: 1
Views: 1906
Reputation: 1653
I found a way to achieve this without any further external configuration required.
The idea is to create a general configuration that applies to all integration tests and use @MockBean
there to replace the real bean. So one should create a class like this under the test
classpath (i.e. that is not scanned during normal application launch):
@Configuration
public class IntegrationTestConfiguration
{
@MockBean
public DeviceStatisticsSyncHandler deviceStatisticsSyncHandler;
}
I was actually surprised that @MockBean
can be used here, but the Javadoc explicitly points that out: Can be used as a class level annotation or on fields in either @Configuration classes, or test classes that are @RunWith the SpringRunner.
.
Upvotes: 0
Reputation: 2340
for me, it's not the case of the condition rather environment-related. I will solve this problem using spring profile.
Step 1: Create an Interface first
public interface DeviceStatisticsSyncHandler {
public void handle(ApplicationReadyEvent event);
}
Step 2: Create an Implementation for production
@Component
@Profile("!test")
public class DeviceStatisticsSyncHandlerImpl implements DeviceStatisticsSyncHandler {
@EventListener
@Override
public void handle(ApplicationReadyEvent event) {
syncDeviceStatisticsDataSync();
}
}
step 3: create an implementation of test
@Component
@Profile("test")
public class DeviceStatisticsSyncHandlerTestImpl implements DeviceStatisticsSyncHandler {
@EventListener
@Override
public void handle(ApplicationReadyEvent event) {
//do Nothing
}
}
final step
All you need to do is set/toggle the property
-Dspring.profiles.active=test
or
-Dspring.profiles.active=prod
Upvotes: 2
Reputation: 42441
One possible option is not to load the DeviceStaticsticsSyncHandler
at all if you're in a test mode.
The "test.mode" is not a good name here, because the production code contains something tightly bound to the tests.
How about the following approach:
@Component
@ConditionalOnProperty(name ="device.stats.handler.enabled", havingValue = "true", matchIfMissing=true)
public class DeviceStatisticsSyncHandler {
// do whatever you need here, but there is no need for "test.mode" enabled related code here
}
Now in Tests you can define a test property "device.stats.handler.enabled=false" on the test itself or even place that definition in src/test/reources/application.properties
so it will be false
for all tests in the module.
An obvious advantage is that this definition is pretty much self explanatory and can be easy understood by other project maintainers.
Upvotes: 2