How to create different Spring context in each test of @TestFactory?

925 Views Asked by At

I am trying to implement CSV based test for my project. (So that adding CSV with input data in test folder will result in new test launched by maven).
For now I use SpringJUnitConfig and override project settings using @Primary. Here is code: (it launches exactly one test based on test settings)

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();
    }
}

In my FrameworkSpringContext.class I declared component scan for both Application packages and test package:

@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());
    }
}

I also overrode settings bean, that is used inside application:

@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);
    }
}

It's working well, but with this approach, I need to copy MySingleTestLauncher and configuration classes as well for each new test. What I want is to use @TestFactory, to create test on per-folder basis. I imagine test launcher to look something like this:

@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();
        }));
    }
    }
}

Each test would be like a new application launch. I want them to be separated, to be sure that test don't mess with each others output. With different spring contexts for each tests, I would easily mock ISettingsProvider based on test settings, and implement different assertions.
So my question is: what is the best practice to initialize spring context for dynamically created tests?
Should I look up into context caching (link below)?
https://docs.spring.io/spring-framework/docs/4.2.0.RC2/spring-framework-reference/html/integration-testing.html#testcontext-ctx-management-caching
It seems to me that creating new application context would be the right thing to do, isolating each test application launch, so caching may not be the best choice here.

1

There are 1 best solutions below

0
On

@DirtiesContext could help It indicates the associated test or class modifies the ApplicationContext. It tells the testing framework to close and recreate the context for later tests.