Tags:
1) Preface
Junit 5 tagging and filtering gives us great flexibility when it comes to inclusion and exclusion of tests during the build phase. Sometimes though we need more fine-grained options as to when a particular test or test group can be executed. Junit 5 gives us the ability to make our tests aware of the environment they are run on and make appropriate decisions based on that. Let us dive right into the hugely flexible feature of conditional execution.
2) Junit 5 os/java version conditional execution
Some of your tests may be written explicitly for a particular operating system. This may include testing system files manipulation, performance testing, application properties verification etc. Junit 5 allows us to narrow down the scope of a test to one or a group of operating systems:
@Test
@EnabledOnOs(LINUX)
void shouldSetFilePermissions_givenLinuxOs() {
@Test
@DisabledOnOs(MAC)
void shouldFinishWithin3Seconds_givenNotMacOs() {
@Test
@EnabledOnOs({ LINUX, WINDOWS })
void shouldWorkPerEnvironmentVariables_givenLinuxOrWindows() {
Apart from choosing the operating system, we can also decide whether certain tests should be run on a given Java Virtual Machine. This may be useful when we are doing a migration from an older version, and some of the modules cannot be run against legacy versions anymore (or the opposite).
@Test
@EnabledOnJre(JAVA_8)
void shouldWork_givenJava8() {
@Test
@EnabledOnJre({ JAVA_10, JAVA_11 })
void shouldWork_givenJava10And11() {
@Test
@DisabledOnJre(JAVA_5, JAVA_6, JAVA_7)
void shouldWork_givenModernJava() {
3) Junit 5 system/environment conditional execution
Going further with conditional execution, we can disable or enable tests based on how the system is set-up. Some of the features may not be active because of this, and some test groups should just be left out in order not to cause unwanted errors.
Let us take a look at how JVM properties can influence that:
@Test
@EnabledIfSystemProperty(named = "https.proxy", matches = "http://.+")
void shouldSendRequestViaSecureConnection() {
@Test
@DisabledIfSystemProperty(named = "os.arch", matches = ".*32.*")
void shouldWork_given64BitArchitecture() {
The global environment properties can also influence the test execution:
@Test
@EnabledIfEnvironmentVariable(named = "db.url", matches = "jdbc:mysql:.*")
void shouldRetrieveUserData_givenDbConnectionPresent() {
@Test
@DisabledIfEnvironmentVariable(named = "mail-server", matches = "false")
void shouldSendMail_whenUserRequestsMoreDetails() {
4) Create your own custom conditional annotations
If we find ourselves using the conditional features of Junit 5 often, we can think about creating our own custom annotations. This is especially handy when we tend to combine the conditions. Adding an additional layer of abstraction would shorten a bit the creation process and level up the documentation factor of our test suite. The code will not be simply polluted with annotations:
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Test
@EnabledIfEnvironmentVariable(named = "db.url", matches = "jdbc:mysql:.*")
@interface TestWithDb {
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Test
@EnabledIfSystemProperty(named = "https.proxy", matches = "http://.+")
@interface TestWithSecureConnection {
}
@TestWithDb
void shouldRetrieveUserData_givenDbConnectionPresent() {
@TestWithSecureConnection
void shouldSendRequestViaSecureConnection() {
5) Conclusion
Some tests do not mind extreme conditions and like to take on challenges. For the rest you have the safety net of conditional execution.