Skip to content

Commit

Permalink
fix(#1115): Create new test context for each Cucumber scenario
Browse files Browse the repository at this point in the history
- Citrus Cucumber Spring object factory must create new test context instance for each scenario
- Using a singleton test context instance for all scenarios leads to unexpected behavior (e.g. when exceptions are added to the test context)
  • Loading branch information
christophd committed Jan 31, 2024
1 parent 9228b01 commit 3b2126f
Showing 1 changed file with 27 additions and 15 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,9 @@ public class CitrusSpringObjectFactory implements ObjectFactory {
/** Test context */
private TestContext context;

/** Test context factory */
private TestContextFactoryBean testContextFactory;

/** Static self reference */
private static CitrusSpringObjectFactory selfReference;

Expand All @@ -64,7 +67,7 @@ public CitrusSpringObjectFactory() {
@Override
public void start() {
delegate.start();
context = getInstance(TestContext.class);
context = createTestContext();
runner = TestCaseRunnerFactory.createRunner(context);
}

Expand All @@ -75,17 +78,6 @@ public void stop() {

@Override
public <T> T getInstance(Class<T> type) {
if (context == null) {
try {
TestContextFactoryBean contextFactoryBean = delegate.getInstance(TestContextFactoryBean.class);
context = contextFactoryBean.getObject();
initializeCitrus(context, contextFactoryBean.getApplicationContext());
} catch (CucumberBackendException e) {
logger.warn("Failed to get proper TestContext from Cucumber Spring application context: " + e.getMessage());
context = CitrusInstanceManager.getOrDefault().getCitrusContext().createTestContext();
}
}

if (TestContext.class.isAssignableFrom(type)) {
return (T) context;
}
Expand All @@ -101,14 +93,34 @@ public <T> T getInstance(Class<T> type) {
return instance;
}

/**
* Creates new test context for a test case. Uses the test context factory loaded by the Spring application context.
* Caches the test context factory to avoid initializing Citrus multiple times.
* Only refreshes the Citrus context in initialization when the Spring application context changes and therefore also the
* test context factory instance is different to the cached one.
* @return new test context instance created from the test context factory.
*/
private TestContext createTestContext() {
try {
TestContextFactoryBean testContextFactoryBean = delegate.getInstance(TestContextFactoryBean.class);
if (this.testContextFactory == null || !this.testContextFactory.equals(testContextFactoryBean)) {
this.testContextFactory = testContextFactoryBean;
initializeCitrus(testContextFactory.getApplicationContext());
}

return testContextFactory.getObject();
} catch (CucumberBackendException e) {
logger.warn("Failed to get proper TestContext from Cucumber Spring application context: " + e.getMessage());
return CitrusInstanceManager.getOrDefault().getCitrusContext().createTestContext();
}
}

/**
* Initialize new Citrus instance only if it has not been initialized before
* or in case given application context is different to that one stored in the Citrus context.
*
* @param context
* @param applicationContext
*/
private void initializeCitrus(TestContext context, ApplicationContext applicationContext) {
private void initializeCitrus(ApplicationContext applicationContext) {
if (CitrusInstanceManager.hasInstance()) {
CitrusContext citrusContext = CitrusInstanceManager.getOrDefault().getCitrusContext();

Expand Down

0 comments on commit 3b2126f

Please sign in to comment.