Use TestContextManager in cucumber-spring
See original GitHub issueSummary
Support TestContextManager
in cucumber-spring
.
Expected Behavior
When using cucumber-spring
@MockBean
(and other annotations) should just work.
public class Example {
@MockBean
private User object;
@Given("there is a User")
public void there_is_a_User() {
when(object.toString()).thenReturn("I've been mocked");
}
@Then("the User is mocked")
public void the_user_is_mocked() throws Exception {
assertThat(object.toString(), equalTo("I've been mocked"));
}
}
Current Behavior
It is currently possible to use @Autowired
e.g.:
public class Example {
@Autowired
private User object;
@Then("the user is real")
public void the_user_is_mocked() throws Exception {
assertThat(object.toString(), equalTo("I am real"));
}
}
But fields annotated with@MockBean
are not mocked, the example fails with a null pointer exception.
Possible Solution
The causes of failure are two fold:
-
There is no spring context declared (
ContextConfiguration
,BootstrapWith
, ect) so theSpringFactory
falls back to some minimal default. This can be resolved by adding@SpringBootTest
to the step definition. -
The SpringFactory does not call
TestContextManager.beforeTestClass()
TestContextManager.prepareTestInstance()
.TestContextManager.beforeTestMethod()
TestContextManager.beforeTestExecution()
TestContextManager.afterTestExecution()
TestContextManager.afterTestMethod()
TestContextManager.afterTestClass()
Instead step definitions are registered as beans in the Spring context. This had the advantage that step definitions can be auto wired into each other and constructor dependency injection just works. However it also puts the step definitions into the spring context which complicates things.
Given that step definitions calling each other is not a best practice I would not mind step definitions were no longer part of the spring context and instead treated as test instances (see SpringJUnit4ClassRunner.createTest). Any dependency injection would have to be done via @Autowired
.
So to implement this properly the following would have to be done:
- Require that all step definitions created have an empty constructor.
- Map the life-cycle methods of the
TestContextManager
to that of theObjectFactory
. - Fail when there is no Spring context declared instead of creating a default.
Your Environment
- Version used:
cucumber-spring:4.0.0
Issue Analytics
- State:
- Created 5 years ago
- Reactions:2
- Comments:18 (12 by maintainers)
Top GitHub Comments
Is there an update on this? I’ve been using the workaround mentioned above, but i would like to use @MockBean in my stepdef classes for better readability of the code.
If you’re using
6.0.0-RC2
you could use something like this:The class annotated with
@CucumberContextConfiguration
is passed to springsTestContextManager
and subject to the same processing the class would be in JUnit. So this should result in the application context being created with a mockedMyService
bean.You’ll have to figure out the edgecase yourself.