Reputation: 6351
I have a Spring Boot application and I'm using spring-boot-starter-test.
I have a bunch of integration tests that insert data into the application using REST calls. I run these with @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
After each test I end up with some data in my database. I want each test to be truly self-contained, but I haven't found a way of doing this. I tried putting @Rollback on each test, but since I am inserting data externally by REST calls this understandably doesn't work.
So previously I resorted to deleting all data between tests, in a rather low-level way, just by executing a delete query (i.e. something like Query deleteProjects = entityManager.createQuery("DELETE FROM Project"); deleteProjects.executeUpdate();
) for each entity after running a test.
However, I recently added an admin user account that will be created in a CommandLineRunner. I found out this CommandLineRunner is also only ran once for all tests combined, so after the first test finishes and all data is deleted, I lose my admin role.
What would be a good way to set this up? I realize starting the whole application takes some time so a complete new startup wouldn't be ideal. Some way to tell Spring to run the CommandLineRunner before each test would be good. I don't want to instantiate and run it myself, that would be quite hacky and I'm not sure how that would work in terms of transactions. I could exclude this admin user account from being deleted in the query but then I'm still hacking around the system.
Upvotes: 0
Views: 1458
Reputation: 8137
Currently you have a chicken and egg problem with needing to have this admin account existing and the Spring context existing for this admin account. What I find a good way to do this is to have a Spring Profile @Profile("test")
and put this on some Component
which creates this admin account you need:
@Component
@Profile("test")
public class CreateAdminBean {
@Autowired
UserRepo repo;
public CreateAdminBean() {
// TODO your job but something like:
User admin = new User();
admin.setAdmin(true);
repo.create(admin);
}
}
If you want your tests to be truly independent of each-other you will need to recreate the context every time and insure your database is wiped each time. This will cost you allot of time and IMO is unnecessary but if you have your reasons you have your reasons. I personally would mock all the services.
You can just have your database JPA Hibernate you would have spring.jpa.hibernate.ddl-auto= create-drop
. I typically don't do this and just have a method which clears all tables and have that run after each test, but that's not what you are asking in your question, and I would expect to see a @DirtiesContext(classMode = ClassMode.AFTER_EACH_TEST_METHOD)
in your test code.
Upvotes: 1