Pages

Conditionally disabling/enabling JUnit 5 Jupiter test

I have an application that uses JDBC for database connectivity, and I want it configurable for running on Oracle DB, MySql, or SQLite.

As we are well aware, any DBMS is entitled of its own approach to SQL . Testing features in this situation could become complex. Luckly, the new (JUnit 5.7) @DisabledIf and @EnabledIf annotations are here to help us.

Let's see what we can use when we deal with the Jupiter test-disabling features.

If we simply don't want to run a test, we have the @Disabled annotation. Clear and brutal. Here I need something more fine-grained.

OS-based features could be appropriately tested by @EnabledOnOs and @DisabledOnOs. Cool, but this is not the current issue.

The annotation family Enabled/Disabled on JRE are very interesting too, but still not applicable here.

We could set a system property and test it through @DisabledIfSystemProperty (or its Enabled companion). That could do. Still, I won't really have any other use for that property in my application out of testing. I'd prefer not use it.

Even worse with @DisabledIfEnvironmentVariable (and Enabled), that require setting a variable at Operating System level. I don't want that my application required such a wide configuration.

Up to JUnit 5.5, there was a powerful couple of annotations, @DisabledIf and @EnabledIf, that made use of a configurable script engine. Very nice indeed. But they have been cut in 5.6. Damn it. (See Nashorn for more information on this point)

Sometimes They Come Back

Since JUnit 5.7, stripped down to the bone, but @DisabledIf and @EnabledIf are back!

We could pass them just a method name in a string, that should be anyone in the current class or a static method if defined in another class.

The method should return a boolean, not accept any parameter, and, when static and external, it has to be referred to using a notation like "com.example.Conditions#isEncryptionSupported".

It could be worse. It could be rainy.

What I did

I have a configuration file where the user set up a few required properties, among them, the DBMS chosen name, something like

dbms.user=me
dbms.password=password
dbms.name=mysql
dbms.url=jdbc:mysql://localhost:3306/me

Then I have a utility class that access the configuration in its static initializer and makes them available to the application.
In it, and this is the clumsy bit, I provide three static boolean methods to fulfill the requirements.

public abstract class Config {
    // ...

    public static boolean isMySql() {
        return active == Dbms.MYSQL;
    }

    public static boolean isOracle() {
        return active == Dbms.ORACLE;
    }

    public static boolean isSqLite() {
        return active == Dbms.SQLITE;
    }
}

Finally, I let JUnit to decide if it should run a test or not referring to those methods.

So, for instance, I want to disable every test on stored procedure for SQLite because it does not support this feature.

@Test
@DisabledIf("jd.Config#isSqLite")
void getCoderSalaryPlain() throws SQLException {
    // ...

When a feature is supported in a specific way by a given DBMS, I enable a test just for it. This test is specific for MySQL

@Test
@EnabledIf("jd.Config#isMySql")
void getCoderSalaryMissingMySql() throws SQLException {
    // ...

OK, I guess you've got the gist. If you want to see the actual code, you could find it on GitHub. Here is the Configuration class and here a JUnit test case that uses both @DisabledIf and @EnabledIf.

No comments:

Post a Comment