When you embrace Quarkus for its supersonic subatomic Java experience, testing is paramount. However, the default behavior of @QuarkusTest can sometimes pull in more than you bargained for, especially when dealing with external dependencies like databases or Redis. Suddenly, your “unit” tests are spinning up Docker containers, slowing down your feedback loop. Fear not, fellow Quarkus enthusiasts! Let’s explore how to effectively disable these external services and keep our unit tests truly isolated.
The Challenge: Unwanted Testcontainers
By default, Quarkus, when encountering configurations for databases or Redis, tends to fire up Testcontainers within @QuarkusTest. While fantastic for integration tests, this overhead is undesirable for quick, focused unit tests. We want to mock, not provision.
The Solution: Strategic Disabling
Here’s a breakdown of the strategies you can employ to reign in those external dependencies:
1. The Power of @TestProfile and Conditional Configuration
This is arguably the most robust and recommended approach.
- Create a Dedicated Test Profile:
- Establish a specific test profile, such as
unit-tests. - Create a corresponding
application-unit-tests.properties(or.yaml) file insrc/test/resources.
- Establish a specific test profile, such as
- Disable Extensions in the Profile:
- Within the profile’s configuration file, explicitly disable the extensions responsible for the external services.
- For example, to disable a PostgreSQL database:
properties quarkus.datasource.enabled=false - To disable Redis:
properties quarkus.redis.enabled=false
- For example, to disable a PostgreSQL database:
- Within the profile’s configuration file, explicitly disable the extensions responsible for the external services.
- Activate the Profile in Your Tests:
- Use the
@TestProfile(YourUnitTestProfile.class)annotation on your test class. - Create a class that implements
io.quarkus.test.junit.QuarkusTestProfileto define the profile.
java import io.quarkus.test.junit.QuarkusTestProfile; import java.util.Set; public class YourUnitTestProfile implements QuarkusTestProfile { @Override public Set<String> getConfigProfiles() { return Set.of("unit-tests"); } }
- Use the
2. Embrace Mocking with @InjectMock
This is the most important part of unit testing.
- Replace Dependencies with Mocks:
- Leverage
@InjectMockto substitute the injected database or Redis clients with Mockito mocks. - This allows you to simulate the behavior of these dependencies without relying on actual external services.
- Leverage
- Example (Mockito):
import io.quarkus.test.junit.QuarkusTest; import io.quarkus.test.InjectMock; import org.junit.jupiter.api.Test; import org.mockito.Mockito; import javax.inject.Inject; import your.redis.RedisClient; @QuarkusTest public class MyServiceTest {@InjectMock RedisClient redisClient; @Inject MyService myService; @Test public void testMyService() { Mockito.when(redisClient.get("key")).thenReturn("mocked value"); // ... your test logic ... }}
3. Conditional Beans (Less Common)
@UnlessBuildPropertyor@IfBuildProperty:- Conditionally register beans based on build properties.
- This allows you to prevent the registration of beans that depend on external services during unit tests.
Key Takeaways
- Unit Tests Should Be Isolated:
- Strive for unit tests that are fast, focused, and independent of external dependencies.
- Configuration Profiles Are Your Friends:
- Use configuration profiles to manage different test environments effectively.
- Mockito and
@InjectMockfor the Win:- Embrace mocking to control the behavior of your dependencies.
By employing these strategies, you can effectively decouple your Quarkus unit tests from external services, leading to faster, more reliable, and more maintainable tests. Happy testing!