Skip to content

Commit 30a291f

Browse files
committed
[Spring] Cleanly stop after failure to start application context
Fixes: #2569
1 parent 2764068 commit 30a291f

File tree

4 files changed

+61
-25
lines changed

4 files changed

+61
-25
lines changed

CHANGELOG.md

+13-15
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
88
## [Unreleased] (In Git)
99

1010
### Added
11+
* [Core] Warn when glue path is passed as file scheme instead of classpath ([#2547](https://github.com/cucumber/cucumber-jvm/pull/2547) M.P. Korstanje)
1112

1213
### Changed
1314

@@ -16,12 +17,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
1617
### Removed
1718

1819
### Fixed
20+
* [Spring] Cleanly stop after failure to start application context
1921

20-
## [7.3.5] (2022-05-10)
21-
22-
### Added
23-
* [Core] Warn when glue path is passed as file scheme instead of classpath ([#2547](https://github.com/cucumber/cucumber-jvm/pull/2547) M.P. Korstanje)
24-
2522
## [7.3.4] (2022-05-02)
2623

2724
### Fixed
@@ -1793,16 +1790,17 @@ in `cucumber.api` stable from now on, with proper deprecation warnings in case s
17931790
17941791
<!-- Releases -->
17951792
[Unreleased]: https://github.com/cucumber/cucumber-jvm/compare/v7.3.4...main
1796-
[7.3.4]: https://github.com/cucumber/cucumber-jvm/compare/v7.3.3-RC1...v7.3.4
1797-
[7.3.3]: https://github.com/cucumber/cucumber-jvm/compare/v7.3.2-RC1...v7.3.3
1798-
[7.3.2]: https://github.com/cucumber/cucumber-jvm/compare/v7.3.1-RC1...v7.3.2
1799-
[7.3.1]: https://github.com/cucumber/cucumber-jvm/compare/v7.3.0-RC1...v7.3.1
1800-
[7.3.0]: https://github.com/cucumber/cucumber-jvm/compare/v7.2.3-RC1...v7.3.0
1801-
[7.2.3]: https://github.com/cucumber/cucumber-jvm/compare/v7.2.2-RC1...v7.2.3
1802-
[7.2.2]: https://github.com/cucumber/cucumber-jvm/compare/v7.2.1-RC1...v7.2.2
1803-
[7.2.1]: https://github.com/cucumber/cucumber-jvm/compare/v7.2.0-RC1...v7.2.1
1804-
[7.2.0]: https://github.com/cucumber/cucumber-jvm/compare/v7.1.0-RC1...v7.2.0
1805-
[7.1.0]: https://github.com/cucumber/cucumber-jvm/compare/v7.0.0-RC1...v7.1.0
1793+
[7.3.4]: https://github.com/cucumber/cucumber-jvm/compare/v7.3.3...v7.3.4
1794+
[7.3.4]: https://github.com/cucumber/cucumber-jvm/compare/v7.3.3...v7.3.4
1795+
[7.3.3]: https://github.com/cucumber/cucumber-jvm/compare/v7.3.2...v7.3.3
1796+
[7.3.2]: https://github.com/cucumber/cucumber-jvm/compare/v7.3.1...v7.3.2
1797+
[7.3.1]: https://github.com/cucumber/cucumber-jvm/compare/v7.3.0...v7.3.1
1798+
[7.3.0]: https://github.com/cucumber/cucumber-jvm/compare/v7.2.3...v7.3.0
1799+
[7.2.3]: https://github.com/cucumber/cucumber-jvm/compare/v7.2.2...v7.2.3
1800+
[7.2.2]: https://github.com/cucumber/cucumber-jvm/compare/v7.2.1...v7.2.2
1801+
[7.2.1]: https://github.com/cucumber/cucumber-jvm/compare/v7.2.0...v7.2.1
1802+
[7.2.0]: https://github.com/cucumber/cucumber-jvm/compare/v7.1.0...v7.2.0
1803+
[7.1.0]: https://github.com/cucumber/cucumber-jvm/compare/v7.0.0...v7.1.0
18061804
[7.0.0]: https://github.com/cucumber/cucumber-jvm/compare/v7.0.0-RC1...v7.0.0
18071805
[7.0.0-RC1]: https://github.com/cucumber/cucumber-jvm/compare/v6.11.0...v7.0.0-RC1
18081806
[6.11.0]: https://github.com/cucumber/cucumber-jvm/compare/v6.10.4...v6.11.0

spring/src/main/java/io/cucumber/spring/CucumberTestContext.java

+5-1
Original file line numberDiff line numberDiff line change
@@ -66,10 +66,14 @@ void registerDestructionCallback(String name, Runnable callback) {
6666
}
6767

6868
void requireActiveScenario() {
69-
if (sessionId == null) {
69+
if (!isActive()) {
7070
throw new IllegalStateException(
7171
"Scenario scoped beans can only be created while Cucumber is executing a scenario");
7272
}
7373
}
7474

75+
boolean isActive() {
76+
return sessionId != null;
77+
}
78+
7579
}

spring/src/main/java/io/cucumber/spring/TestContextAdaptor.java

+13-8
Original file line numberDiff line numberDiff line change
@@ -50,10 +50,10 @@ public final void start() {
5050

5151
private void notifyTestContextManagerAboutBeforeTestMethod() {
5252
try {
53-
Class<?> testClass = delegate.getTestContext().getTestClass();
54-
Object testContextInstance = applicationContext.getBean(testClass);
53+
Class<?> delegateTestClass = delegate.getTestContext().getTestClass();
54+
Object delegateTestInstance = applicationContext.getBean(delegateTestClass);
5555
Method dummyMethod = TestContextAdaptor.class.getMethod("cucumberDoesNotHaveASingleTestMethod");
56-
delegate.beforeTestMethod(testContextInstance, dummyMethod);
56+
delegate.beforeTestMethod(delegateTestInstance, dummyMethod);
5757
} catch (Exception e) {
5858
throw new CucumberBackendException(e.getMessage(), e);
5959
}
@@ -101,8 +101,14 @@ private void registerStepClassBeanDefinition(BeanDefinitionRegistry registry, Cl
101101
}
102102

103103
public final void stop() {
104-
notifyTestContextManagerAboutAfterTestMethod();
105-
CucumberTestContext.getInstance().stop();
104+
// Don't invoke after test method when before test class was not invoked
105+
// this is implicit in the existence of an active the test context
106+
// session. This is not ideal, but Cucumber only supports 1 set of
107+
// before/after semantics while JUnit and Spring have 2 sets.
108+
if (CucumberTestContext.getInstance().isActive()) {
109+
notifyTestContextManagerAboutAfterTestMethod();
110+
CucumberTestContext.getInstance().stop();
111+
}
106112
notifyTestContextManagerAboutAfterTestClass();
107113
}
108114

@@ -116,10 +122,9 @@ private void notifyTestContextManagerAboutAfterTestClass() {
116122

117123
private void notifyTestContextManagerAboutAfterTestMethod() {
118124
try {
119-
Class<?> testClass = delegate.getTestContext().getTestClass();
120-
Object testContextInstance = applicationContext.getBean(testClass);
125+
Object delegateTestInstance = delegate.getTestContext().getTestInstance();
121126
Method dummyMethod = TestContextAdaptor.class.getMethod("cucumberDoesNotHaveASingleTestMethod");
122-
delegate.afterTestMethod(testContextInstance, dummyMethod, null);
127+
delegate.afterTestMethod(delegateTestInstance, dummyMethod, null);
123128
} catch (Exception e) {
124129
throw new CucumberBackendException(e.getMessage(), e);
125130
}

spring/src/test/java/io/cucumber/spring/SpringFactoryTest.java

+30-1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import io.cucumber.core.backend.CucumberBackendException;
44
import io.cucumber.core.backend.ObjectFactory;
5+
import io.cucumber.spring.SpringFactoryTest.FailedContextConfiguration.FailingListener;
56
import io.cucumber.spring.beans.Belly;
67
import io.cucumber.spring.beans.BellyBean;
78
import io.cucumber.spring.beans.DummyComponent;
@@ -22,6 +23,9 @@
2223
import org.springframework.beans.factory.annotation.Autowired;
2324
import org.springframework.beans.factory.annotation.Value;
2425
import org.springframework.test.context.ContextConfiguration;
26+
import org.springframework.test.context.TestContext;
27+
import org.springframework.test.context.TestExecutionListener;
28+
import org.springframework.test.context.TestExecutionListeners;
2529

2630
import java.util.Optional;
2731

@@ -341,6 +345,15 @@ void shouldBeStoppableWhenFacedWithMissingContextConfiguration() {
341345
assertDoesNotThrow(factory::stop);
342346
}
343347

348+
@Test
349+
void shouldBeStoppableWhenFacedWithFailedApplicationContext() {
350+
final ObjectFactory factory = new SpringFactory();
351+
factory.addClass(FailedContextConfiguration.class);
352+
353+
assertThrows(RuntimeException.class, factory::start);
354+
assertDoesNotThrow(factory::stop);
355+
}
356+
344357
@CucumberContextConfiguration
345358
@ContextConfiguration("classpath:cucumber.xml")
346359
public static class WithSpringAnnotations {
@@ -366,7 +379,7 @@ public String getProperty() {
366379
}
367380

368381
@CucumberContextConfiguration
369-
@ContextConfiguration()
382+
@ContextConfiguration
370383
public static class WithEmptySpringAnnotations {
371384

372385
}
@@ -376,4 +389,20 @@ public static class WithoutContextConfiguration {
376389

377390
}
378391

392+
@CucumberContextConfiguration
393+
@ContextConfiguration("classpath:cucumber.xml")
394+
@TestExecutionListeners(FailingListener.class)
395+
public static class FailedContextConfiguration {
396+
397+
public static class FailingListener implements TestExecutionListener {
398+
399+
@Override
400+
public void beforeTestClass(TestContext testContext) {
401+
throw new RuntimeException("Boom");
402+
}
403+
404+
}
405+
406+
}
407+
379408
}

0 commit comments

Comments
 (0)