Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Parameterized beforeEach/beforeAll in JUnit 5

I want to write a test for a small database-like application. This application uses queries and a query should return the correct result. This is easily implemented in JUnit 5, something like

@BeforeEach
void before() {
  database = prepareDatabase();
}

@Test
void testQuery1() {
  assertThat(database.query("query1")).isEqualTo("result1");
}

@Test
void testQuery2() {
  assertThat(database.query("query2")).isEqualTo("result2");
}

....

Now I want to add optimization switches (e.g. a query optimizer or database indices). The query should return the same results regardless of the running optimization switch (optimizations should only change efficiency not results).

For the test this means that I want to run the same methods for slightly other implementations of prepareDatabase() (e.g. one with optimizer, one with index, one with nothing).

I did not yet find a proper extension for this. I thought of duplicating the whole class for each optimization setting or providing the methods from a shared parent class. Yet this does not feel like the JUnit 5 way of doing this task. Maybe someone could point me to a feature that could help me with this problem?

like image 745
CoronA Avatar asked Aug 03 '18 18:08

CoronA


People also ask

How is a parameterized test annotation in JUnit?

Annotation for fields of the test class which will be initialized by the method annotated by Parameters . Annotation for a method which provides parameters to be injected into the test class constructor by Parameterized . Add this annotation to your test class if you want to generate a special runner.

What is BeforeEach JUnit?

@BeforeEach is used to signal that the annotated method should be executed before each @Test method in the current test class.


1 Answers

As always, there is multiple possible ways of achieving your goal. One of them is to use Java inheritance. You don't even need to wire up any advanced JUnit 5 feature, just an old Java concepts.

Create abstract class with your methods and abstract prepareDatabase().

public abstract class QueryTest {

    Database database;

    @BeforeEach
    void before() {
        database = prepareDatabase();
    }

    @Test
    void testQuery1() {
        assertThat(database.query("query1"), is("result1"));
    }

    @Test
    void testQuery2() {
        assertThat(database.query("query2"), is("result2"));
    }

    abstract Database prepareDatabase();

}

Then - based on different variants, create implementations, overriding only this methods.

public class SwitchTrueQueryTest extends QueryTest {

    @Override
    Database prepareDatabase() {
        return new Database(true);
    }

}

public class SwitchFalseQueryTest extends QueryTest {

    @Override
    Database prepareDatabase() {
        return new Database(false);
    }

}

That's it. Nothing more is necessary, reusable tests are in parent class, no need to duplicate.

Report example

like image 192
jkaczynski Avatar answered Sep 30 '22 01:09

jkaczynski