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

[Spring] CucumberBackendException: No qualifying bean of type #2515

Closed
msfci opened this issue Apr 7, 2022 · 11 comments
Closed

[Spring] CucumberBackendException: No qualifying bean of type #2515

msfci opened this issue Apr 7, 2022 · 11 comments

Comments

@msfci
Copy link

msfci commented Apr 7, 2022

When trying to run step defs with abstract class contains all the context configuration spring sees 2 differnt beans parent and stepdef

I'm using spring boot version: 2.6.4 , with Junit 5 and cucumber version 7.2.3

@SpringBootTest(classes = CoreApplication.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@ContextConfiguration(classes = AbstractIntegrationTest.Config.class)
@CucumberContextConfiguration
public abstract class AbstractIntegrationTest implements En {}

@Suite
@IncludeEngines("cucumber")
@SelectClasspathResource("com/example/bdd")
@ConfigurationParameter(key = GLUE_PROPERTY_NAME, value = "com.example.bdd")
public class CucumberIntegrationTest {
}

public class MyStepdefs extends AbstractIntegrationTest{

    public MyStepdefs() {
        When("^client post to \"([^\"]*)\" with valid data$", (String arg0) -> {
        });
        Then("^the client receives status code of (\\d+)$", (Integer arg0) -> {
        });
    }
}

Exception Stack trace:

io.cucumber.core.backend.CucumberBackendException: No qualifying bean of type 'com.orange.ces.core.bdd.AbstractIntegrationTest' available: expected single matching bean but found 2: com.orange.ces.core.bdd.MyStepdefs,com.orange.ces.core.bdd.AbstractIntegrationTest
	at io.cucumber.spring.TestContextAdaptor.notifyTestContextManagerAboutAfterTestMethod(TestContextAdaptor.java:124)
	at io.cucumber.spring.TestContextAdaptor.stop(TestContextAdaptor.java:107)
	at io.cucumber.spring.SpringFactory.stop(SpringFactory.java:161)
	at io.cucumber.core.runner.Runner.disposeBackendWorlds(Runner.java:156)
	at io.cucumber.core.runner.Runner.runPickle(Runner.java:78)
	at io.cucumber.core.runtime.Runtime.lambda$executePickle$6(Runtime.java:128)
	at io.cucumber.core.runtime.CucumberExecutionContext.lambda$runTestCase$3(CucumberExecutionContext.java:151)
	at io.cucumber.core.runtime.RethrowingThrowableCollector.executeAndThrow(RethrowingThrowableCollector.java:23)
	at io.cucumber.core.runtime.CucumberExecutionContext.runTestCase(CucumberExecutionContext.java:151)
	at io.cucumber.core.runtime.Runtime.lambda$executePickle$7(Runtime.java:128)
	at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:515)
	at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
	at io.cucumber.core.runtime.Runtime$SameThreadExecutorService.execute(Runtime.java:249)
	at java.base/java.util.concurrent.AbstractExecutorService.submit(AbstractExecutorService.java:118)
	at io.cucumber.core.runtime.Runtime.lambda$runFeatures$3(Runtime.java:110)
	at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:195)
	at java.base/java.util.stream.SliceOps$1$1.accept(SliceOps.java:199)
	at java.base/java.util.ArrayList$ArrayListSpliterator.tryAdvance(ArrayList.java:1632)
	at java.base/java.util.stream.ReferencePipeline.forEachWithCancel(ReferencePipeline.java:127)
	at java.base/java.util.stream.AbstractPipeline.copyIntoWithCancel(AbstractPipeline.java:502)
	at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:488)
	at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:474)
	at java.base/java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:913)
	at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
	at java.base/java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:578)
	at io.cucumber.core.runtime.Runtime.runFeatures(Runtime.java:111)
	at io.cucumber.core.runtime.Runtime.lambda$run$0(Runtime.java:82)
	at io.cucumber.core.runtime.Runtime.execute(Runtime.java:94)
	at io.cucumber.core.runtime.Runtime.run(Runtime.java:80)
	at io.cucumber.core.cli.Main.run(Main.java:87)
	at io.cucumber.core.cli.Main.main(Main.java:30)
Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'com.orange.ces.core.bdd.AbstractIntegrationTest' available: expected single matching bean but found 2: com.orange.ces.core.bdd.MyStepdefs,com.orange.ces.core.bdd.AbstractIntegrationTest
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveNamedBean(DefaultListableBeanFactory.java:1271)
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveBean(DefaultListableBeanFactory.java:494)
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:349)
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:342)
	at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1172)
	at io.cucumber.spring.TestContextAdaptor.notifyTestContextManagerAboutAfterTestMethod(TestContextAdaptor.java:120)
	... 30 more
@mpkorstanje
Copy link
Contributor

Interesting. Cucumber isn't behaving but the setup you've created is odd too.

Unlike JUnit, all step definition classes are part of the test context. So there is no need to make the CucumberContextConfiguration annotated class abstract or have the step definition class extend it. As long as both step definitions and annotated class are on the glue path things will work.

Is there a reason you are extending this class?

@mpkorstanje
Copy link
Contributor

Note that Cucumber is failing after the test because java8 step definitions are registered dynamically.

This could be made more robust by keeping a reference to the instance of the annotated class in the TestContextAdaptor rather then fetching it again.

at io.cucumber.spring.TestContextAdaptor.notifyTestContextManagerAboutAfterTestMethod(TestContextAdaptor.java:124)
	at io.cucumber.spring.TestContextAdaptor.stop(TestContextAdaptor.java:107

@msfci
Copy link
Author

msfci commented Apr 8, 2022

Yes, I need this abstract class as it's where I'm doing the test setup like initiating the test db container and mock servers for external services, ... etc

and sorry I don't get your point regarding your second comment, can you please give me more explanation on what to do?

@msfci
Copy link
Author

msfci commented Apr 9, 2022

After using v 6.11.0 which contains only one call start for CucumberTestContext as mentioned here #2516 every thing seems to be working fine

So I will be waiting for the fix in 7.x.x version

@mpkorstanje
Copy link
Contributor

Ah cool! Could you try building 2d67224 and trying the snapshot version?

@mpkorstanje
Copy link
Contributor

Release might not happen soon yet. Something in GH actions changed and I don't know what yet.

@msfci
Copy link
Author

msfci commented Apr 10, 2022

Same problem with the new SNAPSHOT version.

@mpkorstanje
Copy link
Contributor

mpkorstanje commented Apr 10, 2022

Ah okay. Then I think it is mostly #2491. The AbstractIntegrationTest should not have been added to the Spring Context because it is an abstract class. And the CucumberContextConfiguration should have been detected on MyStepdefs because it extends a class that is annotated.

That said, I reckon this would also break your setup once you have more then one step definition class that extends the AbstractIntegrationTest.

Yes, I need this abstract class as it's where I'm doing the test setup like initiating the test db container and mock servers for external services, ... etc

Could you show this in a bit more detail. I don't believe either Spring or Cucumber has any meaningful hooks for this that can't be replicated without the use of abstract classes.

@mpkorstanje mpkorstanje changed the title [Spring/ Junit 5] CucumberBackendException: No qualifying bean of type [Spring] CucumberBackendException: No qualifying bean of type Apr 10, 2022
@msfci
Copy link
Author

msfci commented Apr 10, 2022

Yes, I've done some workaround to Define the CucumberBootstrap class which contains the context configuration annotations @CucumberContextConfiguration and @SpringBootTest ,and separated my common code in a different parent abstract class for all the Stepdefs

But actually this worked only with Java not with Java8, I don't know what's is the reason.

@mpkorstanje
Copy link
Contributor

I wouldn't be able to say that with certainty. You'd have to sprinkle some break points around in the SpringFactory and take a look.

@mpkorstanje
Copy link
Contributor

mpkorstanje commented Apr 26, 2022

I'm going to say that using:

@CucumberContextConfiguration
public abstract class AbstractIntegrationTest implements En {}

isn't supported, there should be a single concrete instance of an @CucumberContextConfiguration annotated class for each test execution. And with #2174 I don't see much reason to improve the usability or errors messages.

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

No branches or pull requests

2 participants