-
-
Notifications
You must be signed in to change notification settings - Fork 2k
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
cucumber-cdi2 does not work with weld #2241
Comments
Looking at the code I believe this problem is because glue classes are explicitely added: @Override
public boolean addClass(final Class<?> clazz) {
getInitializer().addBeanClasses(clazz);
return true;
} While in the deltaspike implementation it is not: @Override
public boolean addClass(final Class<?> clazz) {
return true;
} I think if we want to use CDI, it is up to the user to configure the project to make sure step classes will be injected by the CDI provider, however we decide to do it (annotations, include all classes, etc). |
@dcendents it shouldn't since the impl is then able to unify both after scanning. deltaspike just misses this programmatic feature so it was not possible to do. Looks like a weld bug if they duplicate the beans..A maybe quick/temporary workaround can be to check if there is a beans.xml in the module of the class and if so not add the class but we must do it when the module is not a cdi module (which means testing there is no beans.xml or it contains annotated-mode=none and the bean does not have any defining annotation which sounds way too much compared to what the API is expected to do). |
@rmannibucau maybe I don't get the full logic but after stepping through it in the debugger it seems a bit broken to me. I'm using junit5 and have the following cucumber dependencies:
I have a single RunCucumberTest class with the Currently the So the statement "but we must do it when the module is not a cdi module" is false because Furthermore, it means the behavior is completely different for the first scenario and the rest, which with hindsight explains why only the first scenario reported the Ambiguous dependencies problem and all the 50 others succeeded. So either we stop manually adding classes as it does not seems necessary (my preference as it means I can simply drop a default beans.xml) or we cache the classes set to add them to every new CDI container to get the same behavior for all the scenarios. |
@dcendents code was done for junit4 and never had been tested with junit5, I suspect the lifecycle is not yet fully correct. That said:
Yes, the steps must be resolved even when not a CDI bean and it must be resolved with injections, this is the current impl.
No, using an unmanaged class you don't need, you basically inject in an instance managed by yourself (cucumber-cdi2 here).
As explained ^^ it is necessary, typical case is src/main/resources/META-INF/beans.xml and a step "/no annotation/ public clsas MyStep { @Inject MyService service ....}". This is valid and does not work in your described proposal but works in current cucumber-cdi2 impl.
This can work but the description of the behavior with junit platform engine sounds like it is buggy so I would rather investigate this behavior difference rather than using a workaround in cdi2 module for now. |
@rmannibucau I just tested with junit 4 and it is the exact same behavior, I still don't see why we need to add classes manually at the beginning though. Here are the different configurations we want to support:
Unless I'm missing something, the 2 options when the tests are not CDI discoverable have the same result. Am I missing something though? |
There is an assumption that the factory keeps a list of classes and add them to the context as necessary. So essentially: public final class PicoFactory implements ObjectFactory {
private final Set<Class<?>> classes = new HashSet<>();
private MutablePicoContainer pico;
public void start() {
pico = new PicoBuilder().....build();
for (Class<?> clazz : classes) {
pico.addComponent(clazz);
}
pico.start();
}
public void stop() {
pico.stop();
pico.dispose();
}
public boolean addClass(Class<?> clazz) {
if (isInstantiable(clazz) && classes.add(clazz)) {
addConstructorDependencies(clazz);
}
return true;
}
....
} |
That shouldn't happen but happens anyway because the streaming api makes the code look pretty rather then correct. @Override
public void loadGlue(Glue glue, List<URI> gluePaths) {
GlueAdaptor glueAdaptor = new GlueAdaptor(lookup, glue);
gluePaths.stream()
.filter(gluePath -> CLASSPATH_SCHEME.equals(gluePath.getScheme()))
.map(ClasspathSupport::packageName)
.map(classFinder::scanForClassesInPackage)
.flatMap(Collection::stream)
.forEach(aGlueClass -> scan(aGlueClass, (method, annotation) -> {
container.addClass(method.getDeclaringClass());
glueAdaptor.addDefinition(method, annotation);
}));
} |
The problem is not that it is called multiple times, the Weld implementation is a HashSet and I expect the same for openwebbeans There are 2 problems. First, they are not cached like in PicoContainer and it means the first and the other scenarios run with different configurations. Second, this is a problem with Weld, adding classes explicitely while also scanning for CDI beans, Weld complains about ambiguous classes although it is the same class. There are 2 fixes I can see: 1 - Cache the classes and add them on every new container. 2- Stop adding classes manually to the CDI container. I'm trying to push for fix # 2 as it was a pain to understand the problem and I want to prevent that for other users, but obviously I don't want to break any feature so I'm questioning you to tell me if I'm missing something that justifies why addClasses is still needed and does not simply return true like on the deltaspike module. The only thing that it would/could break is a step class injecting another step class, but I don't see why anyone would need that. And even then by adding a beans.xml file they would become managed and it would be possible. |
@rmannibucau how common is it to test a CDI application without a @dcendents Injecting step definitions into other step definitions is something that should be expected to work. While not pretty, or a good practice, it is a feature that makes it possible to refactor step definitions in small increments. So I'd rather not break it on a minor release. However we can schedule this as a breaking change for v7.0.0 and update the documentation to require a |
@mpkorstanje I see you updated weld to version 4 in the readme but it is probably safer to stick with 3.1.6.Final. As per their release notes: "Functionally, Weld 3 and 4 remain identical and both are getting the same treatment and doses of bugfixes. The main difference is that Weld 4 operates with EE 9, meaning it expects you to use it with CDI 3.0 along with the new jakarta package names." I must say I've been out of touch with the java world lately, I was still using CDI 1.1 on widfly 10 I think, so this is the first time I use CDI 2.0 and it is strictly for my unit tests. All I can say is my project works fine with 3.1.6.Final, if I switch to 4.0.0.Final all the tests fail with "No valid CDI implementation found" I suppose we'll need a new cucumber-cdi3 package soon ;-) |
FYI I pushed this PR #2257 to handle more cleanly the "lib" case we talked about, this can enable to make the step handling simpler and assume all are beans at some point skipping the initializer.addBeanClasses. |
…2248) Depending on the CDI implementation used adding bean classes through getInitializer().addBeanClasses(clazz); while also using a beans.xml file to mark all classes in the module as beans results in duplicate bean definitions. By defining step definitions only as beans when not already defined we avoid this problem. Fixes: #2241 Co-authored-by: Daniel Beland <[email protected]> Co-authored-by: Daniel Beland <[email protected]>
Describe the bug
cucumber-cdi2 does not work with weld.
To Reproduce
Steps to reproduce the behavior:
Expected behavior
cucumber-cdi2 unit tests to pass when using weld.
Context & Motivation
I chose to use weld and couldn't make it work until I decided to debug the provided unit tests to understand what I was doing wrong, it seems the problem is global to cucumber-cdi2.
Your Environment
Additional context
It looks like cucumber-cdi2 is adding an explicit bean for every glue class, but then the default behavior for weld is to scan for (all or annotated classes) and will complain about ambiguous dependencies when both are the same class.
I tried to exclude the class from the scan but then I get a ClassCastException on the second scenario (will open another issue for that problem).
The text was updated successfully, but these errors were encountered: