简体   繁体   中英

@BeforeAll JUnit/spring-boot-test alternative that runs when application context starts

I'm writing a @Repository/@Service integration test that leverages an embedded database. In my test class, I would like to preload my database with some data.

I'm currently using @BeforeEach to load in my sample data, however, this code is run upon each test in my class.

Is there any way that I can load in my test data after Spring application context has loaded, but before any test has been run?

My current approach:

@BeforeEach
public void before() {
    repository.save(...); // -> prepopulates repository with sample data
}

@Test
public void testService() {
    service.get(...); // -> gathers existing record
}

@Test
public void deleteById() {
    service.delete(...); // -> deletes existing record
}

However... with this, I am required to flush out the records after every test. Otherwise any unique constraints can easily be violated.

Rather than using @BeforeEach which is required to run before every test... is it possible to load this in in a @BeforeAll kind of fashion that happens after the spring application context has been loaded?

Just add following snippet to your code. This is just like you can do to detect that Spring application is really started.

@Configuration
public class AppConfig implements ApplicationListener<ApplicationReadyEvent> {

    /**
     * This is to indicate in the logs when the application has actually started and everything is loaded.
     */
    @Override
    public void onApplicationEvent(ApplicationReadyEvent event) {
        ApplicationContext context = event.getApplicationContext();
        Environment env = context.getEnvironment();
        // do what you want on application start
    }
}

PS For database manipulation in test @Sql is the best candidate as was mentioned in comment.

Is there any way that I can load in my test data after Spring application context has loaded

Basically yes, I think you can do that:

The idea is to load the SQL data when the application context is started or in the process of being started.

For example, spring boot integration with Flyway works this way (the bean of Flyway is created and loaded). So, in theory, you could merely use Flyway with test migrations that will contain all the relevant SQL scripts of test data generation.

How can you do this technically?

Here is one way:

Create a special bean (just like the way it works with Flyway) that would depend on your repository and in post construct save the data:

@Component
public class SqlGenerationBean {

   @Autowired
   private MyRepository repo;

   @PostConstruct
   public void init() {
      repo.save();
   } 
}

Another way of doing is to create a listener that will be called upon the application context started and again will call the same repo.save() .

In both cases the bean/listener code should not be accessible from production (it's only for tests): so put it somewhere under src/test/java for example

Now once the application context is started you can use a neat trick:

Mark your tests with @Transactional annotation. Spring will wrap the code in an artificial transaction that will be rolled back automatically (even if the test succeeds) so that all the data that you'll modify during the test will be rolled back and basically before each test, you'll have the same state (that is identical to the state of the database when/after the application context starts). Of course, if you use DDL in the test, some databases can't make it a part of transaction but it depends on the database really.

Another interesting point here is that the application context can be cached even between the test cases (created only once), so keep this in mind.

In this case I would just create a constructor for the test class. It will be triggered before everything.

@BeforeEach runs before each tests but after all initialisations .

you can also just use Mockito and mock the result without need to clean and overcomplicate

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM