-
Notifications
You must be signed in to change notification settings - Fork 2.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Provide easy way to clear / repopulate a database in tests without restarting the application #14240
Comments
In my previous project we used database-native features to import/export dumps:
We triggered those via Although we were also using Liquibase for the general database init and productive migrations in that project, we did not use it for database resets in tests. I've never used Flyway. Might be much faster. |
If there is interest, we can pull some of the stuff I have in the JUnit + Flyway Extension. I actually wanted to have it in the Flyway project, but their test annotations are heavily tied to Spring, so I had to write new ones, more generic. This extension is not tied to Quarkus in anyway, so it works as long as you can provide the Datasource that you want to clear / repopulate. If we make it (or pull it to be part of Quarkus) we can integrate it a little bit better. Anyway, I usually point users to that extension when they request something similar :) |
I'm plus one for having a Quarkus specific - more tightly integrated way of doing what your extension does |
@radcortez I suppose as a user of such a Flyway-based reset feature I would need to write Flyway-compatible migrations? |
Well, yes it is the
Ideally, you should be using some sort of tool to handle your database schema / migrations, being Liquibase / Flyway or something else. In that case, it makes sense that the same tool is applied and used into your tests. This allows you to reuse whatever scripts you require to migrate your I think that we may need to provide ways for these tools to hook up into tests and do their thing. We can certainly provide some generic way, but again, if I'm already using one of these tools and have a bunch os script, I don't want to write new schemas / statements in different way just for testing. |
Looking at your extension @radcortez, I think we should pretty much copy what you did for Quarkus with the change being that it would be super tightly integrated. |
Wouldn't mixing flyway and liquibase be a bit confusing? |
Mixing? How so? |
Sure. Feel free to copy what you want. Or if you prefer, I can pick this up and do it. |
Go ahead :) |
|
I guess we just write a similar one for liquibase. Or ideally, try to come up with a way that is able to use one or the other transparently in the API. |
@radcortez I would love to see As at the time of writing this, |
I'm happy to integrate it directly, I just need to find the time to do it :)
Ah, I can probably look into this and fix it in the extension directly. Feel free to report any bugs there for now. |
If you're using Flyway, you just need to have your tests to extend an abstract class like the following: import javax.inject.Inject;
import org.flywaydb.core.Flyway;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
public abstract class BaseTest {
@Inject
Flyway flyway;
@BeforeEach
void migrate() {
flyway.migrate();
}
@AfterEach
void clean() {
flyway.clean();
}
} |
I tried the BaseTest approach by injecting Flyway, but unfortunately @QuarkusIntegrationTest does not allow to use @Inject.
I've also tried adding @TestTransaction to each integration test class, but that doesn't help. I'm using h2 database for testing (stored to filestystem). |
Instead of injecting, you may probably lookup the |
I see that I have a dependency quarkus-arc included. Is that sufficient? |
|
When I do that in a @beforeeach, Arc.container() returns null. |
Ah my bad. Probably because integration tests don't run in the same instance as the app. Try creating a JAX-RS endpoint and invoking it in your test using RedtAssured, similar to what's done in https://github.com/quarkusio/quarkus/blob/main/integration-tests/flyway/src/main/java/io/quarkus/it/flyway/FlywayFunctionalityResource.java |
OK, I'll have a look at that. Initially I was not using flyway at all (since we're using another framework within the company to deal with db changes). I was looking for a way to create the schema based on a schema.sql instead of using the entities (as we do with spring), but couldn't find a way to do that with Quarkus (#30193), except for using the Flyway approach. So for now I'm using flyway so I get the correct schema creation. |
Implementing a FlywayResource with a migrate and clean endpoint did the trick, although it's a bit cumbersome that you have to implement a specific resource for this. The thing I'm not sure about is that we're now adding something to the production code only for testing purposes. Also we should add restrictions that not just anybody can call these endpoints. And of course also add unittests for the newly introduced code ;-) I now have a FlywayResource as such:
The FlywayModelCreator:
And the model itself:
And then an integrationtest as such:
And the base class:
Mind though that we seem no longer be able to use the @TestHTTPEndpoint on the integration test itself as such:
because this will mess up the flyway path. If the baseUrl for the CommandResource would be "/v1/command", then the flyway url would become "/v1/command/v1/flyway" instead of "/v1/flyway". So I ended up removing the @TestHTTPEndpoint and explicitly set the url in the post/get, etc.:
|
Indeed: https://stackoverflow.com/questions/71022392/quarkus-quarkustest-vs-quarkusintegrationtest |
You can also create an |
Would there be any other way to clear de database before/after running each QuarkusIntegrationTest? The above with Flyway works, but unfortunately we can no longer use Flyway. The company uses it's own tooling for rolling out db changes. For simple @QuarkusTest (or even unit tests without using @QuarkusTest), where we test the repository, we can clear the database ourselves since we can inject some
Obviously we cannot do the above in a @QuarkusIntegrationTest because of the beforementioned reasons (not being able to use @Inject in @QuarkusIntegrationTest). So my question: are there alternatives for clearing the db contents before/after eacht QuarkusIntegrationTest? |
For integration tests, you need to create the datasource directly and then run the scripts (kind of like Flyway does). |
I came up with a different approach: we already had some delete resource which just deletes all records from the database, so I call that in the @beforeeach and @AfterEach of the integration test to clean up (no need to inject anything in the integration test in this case, just call the resource with RestAssured). These delete resources are now in the production code as well though, but we only need that for testing purposes. Next step is to take out these delete resources into a separate module which we don't deploy to production. Just like Gastaldi recommended to do for the FlywayResource mentioned earlier. |
Description
Users often want to clear and repopulate their database before every test.
We should provide some out of the box functionality to make that easy when Hibernate and / Flyway or Liquibase are used.
Implementation ideas
@famod IIRC, you already had something like this?
The text was updated successfully, but these errors were encountered: