@BeforeAll是JUnit/spring-boot-test的替代,它在应用程序上下文启动时运行。

huangapple go评论89阅读模式
英文:

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

问题

我正在编写一个@Repository/@Service集成测试,利用了一个嵌入式数据库。在我的测试类中,我想要预加载一些数据到我的数据库中。

我目前正在使用@BeforeEach在每个测试运行之前加载我的示例数据,然而,这段代码会在我类中的每个测试执行时都运行。

是否有任何方式可以在Spring应用程序上下文加载完成后,但在任何测试运行之前加载我的测试数据呢?

我的当前方法:

@BeforeEach
public void before() {
    repository.save(...); // -> 使用示例数据预加载存储库
}

@Test
public void testService() {
    service.get(...); // -> 获取现有记录
}

@Test
public void deleteById() {
    service.delete(...); // -> 删除现有记录
}

然而... 使用这种方法,我需要在每个测试之后清除记录。否则,任何唯一约束都很容易被违反。

与其使用每个测试之前都要运行的@BeforeEach,是否有可能以一种类似@BeforeAll的方式加载数据,该方式会在Spring应用程序上下文加载完成后发生?

英文:

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?

答案1

得分: 1

在这种情况下,我只需为测试类创建一个构造函数。它将在所有操作之前被触发。

@BeforeEach 在每个测试之前运行,但在所有初始化之后运行。

您还可以使用Mockito并模拟结果,无需进行清理和过度复杂化。

英文:

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

答案2

得分: 1

只需将以下代码段添加到您的代码中。这就像您可以执行以下操作来检测Spring应用程序是否真正启动。

@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();
        // 在应用程序启动时执行您想要的操作
    }
}

P.S. 对于在测试中进行数据库操作,@Sql 是最佳选择,如评论中所提到的。

英文:

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&lt;ApplicationReadyEvent&gt; {

    /**
     * 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
    }
}

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

答案3

得分: 1

>有没有办法在Spring应用程序上下文加载后加载我的测试数据?

基本上是的,我认为你可以这样做:

思路是在应用程序上下文启动或正在启动的过程中加载SQL数据。

例如,Spring Boot与Flyway集成的工作方式就是这样的(创建和加载Flyway的bean)。因此,理论上你可以仅使用带有包含所有相关测试数据生成SQL脚本的测试迁移的Flyway。

你可以如何在技术上做到这一点?

以下是一种方法:

创建一个特殊的bean(就像Flyway的工作方式一样),该bean将依赖于你的repository,并在post construct阶段保存数据:

@Component
public class SqlGenerationBean {

   @Autowired
   private MyRepository repo;

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

另一种方法是创建一个监听器,在应用程序上下文启动时将被调用,并再次调用相同的repo.save()

在这两种情况下,bean/监听器代码不应该从生产环境中访问(只用于测试):因此,将其放在例如src/test/java下的某个位置。

现在,一旦应用程序上下文启动,你可以使用一个巧妙的技巧:

使用@Transactional注解标记你的测试。Spring将代码包装在人工事务中,该事务将自动回滚(即使测试成功),以便在测试期间修改的所有数据都将被回滚,基本上在每个测试之前,你将拥有相同的状态(与应用程序上下文启动后的数据库状态相同)。当然,如果在测试中使用DDL,一些数据库可能无法将其作为事务的一部分,但这实际上取决于数据库。

这里还有一个有趣的观点,应用程序上下文甚至可以在测试用例之间被缓存(只创建一次),所以请记住这一点。

英文:

>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.

huangapple
  • 本文由 发表于 2020年9月3日 03:41:17
  • 转载请务必保留本文链接:https://go.coder-hub.com/63712543.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定