'How do you achieve Integration tests in Quarkus without @DirtiesContext?

With Spring Boot, I use @DirtiesContext to ensure the database is cleared before each test case.

There is no @DirtiesContext annotation with Quarkus AFAIK. Instead @TestTransaction is suggested. This way the changes made by the test case are rolled back at the end of the test case. This works fine for unit tests. But, I am struggling to see how I can use this for integration tests.

My integration tests use rest assured to make rest calls to the controller. On one side, I don’t think it would be a good idea to use @TestTransaction in the controller. Even if I did, the data would be wiped when the rest call returns. And if I use @Transaction in the controller, I have no way to wipe the database for the next test case.

So, my question is how do you folks resolve this? How do you make sure you have a clean context when doing integration tests.



Solution 1:[1]

It seems Spring's @DirtiesContext is a:

Test annotation which indicates that the ApplicationContext associated with a test is dirty and should therefore be closed and removed from the context cache.

Use this annotation if a test has modified the context — for example, by modifying the state of a singleton bean, modifying the state of an embedded database, etc. Subsequent tests that request the same context will be supplied a new context.

This is quite different than clearing the database by rolling back the current transaction: this destroys and recreates the entire Spring context.

The same effect can be achieved using Quarkus @QuarkusTestProfile, described here as:

If a test has a different profile to the previously run test then Quarkus will be shut down and started with the new profile before running the tests. This is obviously a bit slower, as it adds a shutdown/startup cycle to the test time, but gives a great deal of flexibility.

If however all you need is to make sure that the transaction is rolled back after the test, all you need to do is to annotate the test method, not the controller with io.quarkus.test.TestTransaction, as described here:

You can use the standard Quarkus @Transactional annotation on tests, but this means that the changes your test makes to the database will be persistent. If you want any changes made to be rolled back at the end of the test you can use the io.quarkus.test.TestTransaction annotation. This will run the test method in a transaction, but roll it back once the test method is complete to revert any database changes.

Your application code will run in the transaction started by the test method, do its thing that you can then test in the test method and finally rollback to wipe any persistent state that participates in the transaction. This has a few pitfalls: (1) If at some point your logic starts a new transaction, this is not rolled back automatically. (2) If your logic alters some kind of state that does not participate in the transaction, this change is not rolled back.

Solution 2:[2]

@TestTransaction should start a transaction that is ready for rollback and can be propagated to transactional methods in white-box testing. However, when you use black-box testing like calling your REST layer through rest-assured, you are calling a Servlet with its own Threadpool. As the transaction is associated with a Thread, your REST-call will create a new transaction eventually and this one will commit (your TestTransaction is associated with the main thread only). I am trying to solve this by resetting the test data manually. DbUnit would also be a solution. Spring has the same behaviour afaik.

@DirtiesContext has nothing to do with the DB transaction. It is about the ApplicationContext and if its state was manipulated (e.g. you mocked a bean in one test and the next test expects the real thing). The only reason why this annotation is needed is that Spring Boot by default caches the context, instead of restarting for each test. If you change your jvm test fork-mode to class, Spring TestContext will boot for each test class and you cannot even have this issue. However, this means your tests run a lot slower.

@QuarkusTestProfile, as mentioned by Nikos Paraskevopoulos seems to be the solution to this with Quarkus. Basically defining the TestContext for each test separately. A clean solution in fact, that you have to implement in Spring yourself. What i do not know is if multiple TestContexts are cached in Quarkus (Spring does that, given enough available memory), so ordering the tests as mentioned in the Quarkus guide seems advisable for best performance.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Nikos Paraskevopoulos
Solution 2 A. Schwarz