Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

@MockBean not Working with SpringBootTest and Junit5 #2654

Closed
sashokbg opened this issue Dec 6, 2022 · 9 comments Β· Fixed by #2661
Closed

@MockBean not Working with SpringBootTest and Junit5 #2654

sashokbg opened this issue Dec 6, 2022 · 9 comments Β· Fixed by #2661

Comments

@sashokbg
Copy link

sashokbg commented Dec 6, 2022

πŸ‘“ What did you see?

When running a SpringBootTest with JUnit5 (Jupiter) all @MockBean annotations are not populated.

βœ… What did you expect to see?

Running the same test without cucumber configuration works with no issue.

πŸ“¦ Which tool/library version are you using?

Java - JDK 17
SpringBoot 2.7
Junit Jupiter - 5.8.2
cucumber-java - 7.8.1
cucumber-spring - 7.8.1
cucumber-junit-platform-engine - 7.8.1

πŸ”¬ How could we reproduce it?

Cucumber Test as described in the documentation

@Suite
@IncludeEngines("cucumber")
@SelectClasspathResource("features")
@ConfigurationParameter(key = GLUE_PROPERTY_NAME, value = "com.proxym.bankerise.backend.messagecenter.domain")
@ConfigurationParameter(key = FILTER_TAGS_PROPERTY_NAME, value = "@Active")
public class MessageCenterApplicationIT {

}

StepsFile

@CucumberContextConfiguration
@SpringBootTest(classes = TestConfig.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@SpringJUnitConfig
public class MessageCenterSteps {
    @Autowired
    private ApplicationContext applicationContext; // <-- works properly injected

    @MockBean
    private EmailChannelAdapter emailChannelAdapter; <-- not working


This text was originally generated from a template, then edited by hand. You can modify the template here.

@mpkorstanje
Copy link
Contributor

mpkorstanje commented Dec 6, 2022

Could you sprinkle some breakpoints in the MockitoTestExecutionListener and see what happens?

I would expect something goes wrong when prepareTestInstance is called.

@sashokbg
Copy link
Author

sashokbg commented Dec 6, 2022

Hello @mpkorstanje , thank you for prompt response !

I was already debugging and it turns out the spring context gets properly populated with the mocked beans.

I put a breakpoint in my @BeforeAll and did inject the Spring ApplicationContext then did in evaluate mode "context.getBean(EmailChannelAdapter.class)" and it returns the mock.

This means that the problem is in the injection of the beans.

After following your advice:

I found out that inside the following method in the MockitoTestExecutionListenr, if I set the property REINJECT_DEPNDENCIES_ATTRIBUTES to true - then everything works fine.

@Override
public void beforeTestMethod(TestContext testContext) throws Exception {
	if (Boolean.TRUE.equals(
			testContext.getAttribute(DependencyInjectionTestExecutionListener.REINJECT_DEPENDENCIES_ATTRIBUTE))) {
		initMocks(testContext);
		reinjectFields(testContext);
	}
}

Any help is greatly appreciated :)

@mpkorstanje
Copy link
Contributor

mpkorstanje commented Dec 6, 2022

Sounds like #2572, specifically we don't invoke prepareTestInstance.

private void notifyTestContextManagerAboutBeforeTestMethod() {
try {
Class<?> delegateTestClass = delegate.getTestContext().getTestClass();
delegateTestInstance = applicationContext.getBean(delegateTestClass);
Method dummyMethod = TestContextAdaptor.class.getMethod("cucumberDoesNotHaveASingleTestMethod");
delegate.beforeTestMethod(delegateTestInstance, dummyMethod);
} catch (Exception e) {

As you can see we create a test instance by pulling it from the application context. This ensures the test instance is a bean that can be injected into other step definition class instances and others can be injected into it.

JUnit doesn't have this requirement (only one test class ever). So JUnit creates the test instance using the zero-arg constructor and outside of the application context. By invoking prepareTestInstance JUnit then auto wires the spring and mock beans.

I have no idea what would happen if we do call prepareTestInstance on a bean.

@mpkorstanje
Copy link
Contributor

mpkorstanje commented Dec 6, 2022

@sashokbg
Copy link
Author

sashokbg commented Dec 7, 2022

Hello @mpkorstanje and thank you for your help.

Unfortunately I don't really understand how to properly configure the AutowireCapableBeanFactory for cucumber context :( - do you have any examples of how it is done ? I tried searching on the internet but results are sparse.

@mpkorstanje
Copy link
Contributor

If you want to, you'd have to fix it in the [TestContextAdaptor.java](https://github.com/cucumber/cucumber-jvm/blob/51cde873cc860c33665c777ffe3bdbb06612941e/cucumber-spring/src/main/java/io/cucumber/spring/TestContextAdaptor.java#L52-L58) and send a pull request.

@sashokbg
Copy link
Author

sashokbg commented Dec 7, 2022

I will try to do that tonight after work hours - being busy at the moment.
Thank you

@mpkorstanje
Copy link
Contributor

Cheers. No rush though.

@sashokbg
Copy link
Author

sashokbg commented Dec 8, 2022

@mpkorstanje #2655 opened. I mentioned you in the second commit message since you solved the issue :)

sashokbg added a commit to sashokbg/cucumber-jvm that referenced this issue Dec 8, 2022
mpkorstanje added a commit that referenced this issue Dec 11, 2022
To make writing tests with Spring easier Spring provides a
`TestContextManager`. This classes provides call backs for various
`TestExecutionListeners`.

These are then used by various extensions such as
the `MockitoTestExecutionListener` which injects `@MockBeans` into test
instances. When all methods are not invoked this leads to problems such as
(#2654,#2655,#2656)

While this was initially (#1470) not a problem, it appears that various
listener implementations have started to assume that all methods would be
invoked.

Closes: #2655
Fixes: #2654, #2572
mpkorstanje added a commit that referenced this issue Dec 11, 2022
To make writing tests with Spring easier Spring provides a
`TestContextManager`. This classes provides call backs for various
`TestExecutionListeners`.

These are then used by various extensions such as
the `MockitoTestExecutionListener` which injects `@MockBeans` into test
instances. When all methods are not invoked this leads to problems such as
(#2654,#2655,#2656)

While this was initially (#1470) not a problem, it appears that various
listener implementations have started to assume that all methods would be
invoked.

Closes: #2655
Fixes: #2654, #2572
mpkorstanje added a commit that referenced this issue Dec 11, 2022
To make writing tests with Spring easier Spring provides a
`TestContextManager`. This classes provides call backs for various
`TestExecutionListeners`.

These are then used by various extensions such as
the `MockitoTestExecutionListener` which injects `@MockBeans` into test
instances. When all methods are not invoked this leads to problems such as
(#2654,#2655,#2656)

While this was initially (#1470) not a problem, it appears that various
listener implementations have started to assume that all methods would be
invoked.

Closes: #2655
Fixes: #2654, #2572
mpkorstanje added a commit that referenced this issue Dec 11, 2022
To make writing tests with Spring easier Spring provides a
`TestContextManager`. This classes provides call backs for various
`TestExecutionListeners`.

These are then used by various extensions such as
the `MockitoTestExecutionListener` which injects `@MockBeans` into test
instances. When all methods are not invoked this leads to problems such as
(#2654,#2655,#2656)

While this was initially (#1470) not a problem, it appears that various
listener implementations have started to assume that all methods would be
invoked.

Closes: #2655
Fixes: #2654, #2572
mpkorstanje added a commit that referenced this issue Dec 11, 2022
To make writing tests with Spring easier Spring provides a
`TestContextManager`. This classes provides call backs for various
`TestExecutionListeners`.

These are then used by various extensions such as
the `MockitoTestExecutionListener` which injects `@MockBeans` into test
instances. When all methods are not invoked this leads to problems such as
(#2654,#2655,#2656)

While this was initially (#1470) not a problem, it appears that various
listener implementations have started to assume that all methods would be
invoked.

Closes: #2655
Fixes: #2654, #2572
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants