Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to unit test CDI with weld-se?

I want to use weld-se for unit testing CDI. However, I am stuck with this problem that Weld cannot resolve beans. I created a mini-project to demonstrate the problem with gradle for building.

I have the following files in the <project-root> folder:

./build.gradle
./src/main/java/cdi/Book.java
./src/main/resources/META-INF/beans.xml
./src/test/java/cdi/BookTest.java
./src/test/resources/META-INF/beans.xml

The content of each file is listed below.

build.gradle

apply plugin: 'java'    
repositories {
    mavenCentral()
}    
dependencies {
    compile 'org.jboss.weld.se:weld-se:2.0.4.Final'
    testCompile 'junit:junit:4.11'
}

Book.java

package cdi;    
public class Book {
    private String title;    
    public String getTitle() {
        return title;
    }    
    public void setTitle(String title) {
        this.title = title;
    }
}

BookTest.java

package cdi;
import org.jboss.weld.environment.se.Weld;
import org.jboss.weld.environment.se.WeldContainer;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
public class BookTest {
    private static Weld weld;
    private static WeldContainer weldContainer;

    @BeforeClass
    public static void setupClass() {
        weld = new Weld();
        weldContainer = weld.initialize();
    }

    @AfterClass
    public static void teardownClass() {
        weld.shutdown();
    }

    @Test
    public void dummyTest() {
        Book book = weldContainer.instance().select(Book.class).get();
        book.setTitle( "foobar");
        assertEquals("foobar", book.getTitle());
    }
}

beans.xml(The two beans.xml under main/ and test/ are identical.)

<beans xmlns="http://xmlns.jcp.org/xml/ns/javaee"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee 
                           http://xmlns.jcp.org/xml/ns/javaee/beans_1_1.xsd"
       version="1.1" bean-discovery-mode="all">
</beans>

When I build the project with gradle clean build, I get an error, which is listed below. I googled around, but couldn't make it work.

Thank you very much for your help.

org.jboss.weld.exceptions.UnsatisfiedResolutionException: WELD-001308 Unable to resolve any beans for Types: [class cdi.Book]; Bindings: [QualifierInstance{annotationClass=interface javax.enterprise.inject.Any, values={}, hashCode=868729182}]
    at org.jboss.weld.manager.BeanManagerImpl.getBean(BeanManagerImpl.java:824)
    at org.jboss.weld.bean.builtin.InstanceImpl.get(InstanceImpl.java:78)
    at cdi.BookTest.dummyTest(BookTest.java:29)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
    at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
    at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
    at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecuter.runTestClass(JUnitTestClassExecuter.java:80)
    at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecuter.execute(JUnitTestClassExecuter.java:47)
    at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassProcessor.processTestClass(JUnitTestClassProcessor.java:69)
    at org.gradle.api.internal.tasks.testing.SuiteTestClassProcessor.processTestClass(SuiteTestClassProcessor.java:49)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at org.gradle.messaging.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:35)
    at org.gradle.messaging.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
    at org.gradle.messaging.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:32)
    at org.gradle.messaging.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:93)
    at com.sun.proxy.$Proxy2.processTestClass(Unknown Source)
    at org.gradle.api.internal.tasks.testing.worker.TestWorker.processTestClass(TestWorker.java:103)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at org.gradle.messaging.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:35)
    at org.gradle.messaging.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
    at org.gradle.messaging.remote.internal.hub.MessageHub$Handler.run(MessageHub.java:355)
    at org.gradle.internal.concurrent.DefaultExecutorFactory$StoppableExecutorImpl$1.run(DefaultExecutorFactory.java:66)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
    at java.lang.Thread.run(Thread.java:724)
like image 332
JBT Avatar asked Sep 29 '13 17:09

JBT


3 Answers

I had the exact same type of problem and it is caused by the META-INF/beans.xml file being put into build/resources/ instead of build/classes by Gradle.

Weld will not scan the classes without the beans.xml file as far as I can understand.

An ugly fix is to change the build.gradle file to copy the files before running the test. This works for me and I do not know about any undesireable side effects at the moment.

Changes to the Gradle file.

test.doFirst {
    copy {
        from 'build/resources/main/META-INF/beans.xml'
        into 'build/classes/main/META-INF/'
    }
    copy {
        from 'build/resources/test/META-INF/beans.xml'
        into 'build/classes/test/META-INF/'
    }
}
like image 81
oyse Avatar answered Nov 04 '22 22:11

oyse


You should give "needle" a try: http://needle.spree.de/overview.

It takes care of simple mocking/DI tasks for you and does not require a full stack container. In your case, you could just use

@Rule
public final NeedleRule needle = new NeedleRule();
@Inject
private Book book;
...
like image 42
Jan Galinski Avatar answered Nov 04 '22 23:11

Jan Galinski


Also I created CDI-Unit http://jglue.org/cdi-unit/

There is an example gradle project in the source tree: https://github.com/BrynCooke/cdi-unit/tree/master/cdi-unit-tests-gradle

like image 41
Bryn Avatar answered Nov 04 '22 23:11

Bryn