如何在@TestFactory 的每个测试中创建不同的 Spring 上下文?
Posted
技术标签:
【中文标题】如何在@TestFactory 的每个测试中创建不同的 Spring 上下文?【英文标题】:How to create different Spring context in each test of @TestFactory? 【发布时间】:2021-09-16 10:13:57 【问题描述】:我正在尝试为我的项目实施基于 CSV 的测试。 (以便在测试文件夹中添加带有输入数据的 CSV 将导致 maven 启动新测试)。 现在我使用 SpringJUnitConfig 并使用 @Primary 覆盖项目设置。 这是代码:(它会根据测试设置启动一个测试)
package com.bch.score.test.framework;
@SpringJUnitConfig(FrameworkSpringContext.class)
public class MySingleTestLauncher
@Autowired
public MainApplicationService service;
@Autowired
public TestDbService dbPreparationService;
@Autowired
public IFrameworkDatabaseConfig dbSettings;
@Autowired
public TestOutputChecker outputChecker;
@Test
public void testSingleCase()
dbPreparationService.fillDatabase(dbSettings);
service.launchApp();
outputChecker.checkResult();
在我的 FrameworkSpringContext.class 中,我声明了应用程序包和测试包的组件扫描:
@Configuration
@EnableAutoConfiguration(exclude=DataSourceAutoConfiguration.class)
@ComponentScan(value = "com.bch.score.test.framework.config", "com.bch.score.cmd")
public class FrameworkSpringContext
private final ISettingsProvider settings;
@Autowired
public FrameworkSpringContext(ISettingsProvider settings)
this.settings = settings;
@Bean
public TestDbService service()
return new TestDbService();
@Bean
public TestOutputChecker outputAssertion()
return new TestOutputChecker();
@Bean
public IFrameworkDatabaseConfig dbSettings()
return new FrameworkDatabaseConfigImpl(settings.getUrl(), settings.getSchema(), settings.getLogin(), settings.getPassword());
我还覆盖了在应用程序中使用的设置 bean:
@PropertySource("classpath:score-framework.properties")
@Configuration
public class SettingsConfigurationFramework
@Primary
@Bean(name = "testSettings")
public ISettingsProvider settingsProvider(MessageSource messageSource, Environment environment)
return new SettingsProviderImpl(messageSource, environment);
它运行良好,但使用这种方法,我还需要为每个新测试复制 MySingleTestLauncher 和配置类。我想要的是使用@TestFactory,在每个文件夹的基础上创建测试。我想测试启动器看起来像这样:
@SpringJUnitConfig(FrameworkSpringContext.class)
public class MultipleTestLauncher
@Autowired
public TestDbService dbPreparationService;
@Autowired
public Function<String, IFrameworkDatabaseConfig> dbSettingsFactory;
@Autowired
public TestOutputChecker outputChecker;
@TestFactory
public Collection<DynamicTest> testTests() throws IOException
List<Path> subFolders = Files.list(Paths.get("src", "test", "resources", "framework", "tests"))
.filter(path -> path.getFileName().toString().startsWith("test_"))
.collect(Collectors.toList());
List<DynamicTest> dynamicTests = new ArrayList<>();
for (Path testPath : subFolders)
String currentTestFolder = testPath.getFileName().toString();
dynamicTests.add(DynamicTest.dynamicTest(currentTestFolder, () ->
IFrameworkDatabaseConfig dbSettings = dbSettingsFactory.apply(currentTestFolder);
dbPreparationService.fillDatabase(dbSettings);
//TODO somehow create new Spring context for each app launch...
//TODO getTestContext().getBean(MainApplicationService.class).launchApp();
outputChecker.checkResult();
));
每次测试都像是一个新的应用程序启动。我希望将它们分开,以确保测试不会混淆彼此的输出。 为每个测试使用不同的 spring 上下文,我可以轻松地根据测试设置模拟 ISettingsProvider,并实现不同的断言。 所以我的问题是:为动态创建的测试初始化 Spring 上下文的最佳做法是什么?我应该查看上下文缓存(下面的链接)吗?https://docs.spring.io/spring-framework/docs/4.2.0.RC2/spring-framework-reference/html/integration-testing.html#testcontext-ctx-management-caching 在我看来,创建新的应用程序上下文是正确的做法,隔离每个测试应用程序的启动,因此缓存可能不是这里的最佳选择。
【问题讨论】:
【参考方案1】:@DirtiesContext 可以提供帮助 它表示关联的测试或类修改了 ApplicationContext。它告诉测试框架关闭并为以后的测试重新创建上下文。
【讨论】:
以上是关于如何在@TestFactory 的每个测试中创建不同的 Spring 上下文?的主要内容,如果未能解决你的问题,请参考以下文章
如何在 laravel 路由中创建不包括某些 slug 的 slug 路由?
我可以同时运行@TestFactory生成的Junit动态测试吗?