Easy testing of CDI components with Weld and JUnit4
Posted by mkouba in Martin Kouba's Blog on Jan 24, 2017 4:01:50 AMThere is no doubt that unit/component testing is essential for most of the applications. Sometimes the component under the test needs to communicate with other components. This is where we usually reach for mocking frameworks. And if it's not sufficient (or too complicated) there are still integration tests. Integration tests are usually more time and resource-consuming though. And for CDI components mocks might very oftten become too complex. Not to mention the services provided by the container (interceptors, decorators, events, programmatic lookup, etc.) are hard to mock (if at all). That's the reason why Arquillian has an embedded Weld container. Recently, the first beta version (beta but stable and ready to use) of Weld JUnit extensions was released. Well, it's just another tool for testing CDI components. So how does it differ from other tools such as Arquillian, DeltaSpike Test Control and CDI-Unit? Well, it's really simple, easy to use, fast and it leverages the powerful Weld SE Bootstrap API.
Get Started
Just add one dependency to your pom.xml:
<dependency> <groupId>org.jboss.weld</groupId> <artifactId>weld-junit4</artifactId> <version>${version.weld-junit}</version> </dependency>
NOTE: At the time I wrote this article the artifact was only available in JBoss Maven repository. However, it should reach the Maven Central sooner or later.
And then add WeldInitiator
test rule to your test:
import static org.junit.Assert.assertEquals; import org.junit.Rule; import org.junit.Test; public class SimpleTest { @Rule public WeldInitiator weld = WeldInitiator.of(Foo.class); @Test public void testFoo() { // Note that Weld container is started automatically // WeldInitiator can be used to perform programmatic lookup of beans assertEquals("baz", weld.select(Foo.class).get().getBaz()); // WeldInitiator can be used to fire a CDI event weld.event().select(Baz.class).fire(new Baz()); } }
org.jboss.weld.junit.WeldInitiator
is a test rule (JUnit 4.9+) which starts/stops a Weld container per test method execution. The container is configured through the Weld SE Bootstrap API, i.e. a provided org.jboss.weld.environment.se.Weld
instance. A convenient static method WeldInitiator.of(Class<?>...)
is also provided - in this case, the container is optimized for testing purposes (with automatic discovery and concurrent deployment disabled) and only the given bean classes are considered. WeldInitiator
also implements javax.enterprise.inject.Instance
and therefore might be used to perform programmatic lookup of bean instances. It's also possible to use the convenient static method WeldInitiator.ofTestPackage()
- the container is optimized for testing purposes and all the classes from the test class package are added. Sometimes, the programmatic lookup can imply unnecessary overhead, e.g. an annotation literal must be used for parameterized types and qualifiers with members. WeldInitiator.inject(Object)
instructs the rule to inject the given non-contextual instance once the container is started, i.e. during each test method execution:
public class InjectTest { @Rule public WeldInitiator weld = WeldInitiator.of(Foo.class).inject(this); // Gets injected by WeldInitiator when testFoo() is about to be run @Inject @MyQualifier Foo foo; @Test public void testFoo() { assertEquals(42, foo.getValue()); } }
And that's basically all. The Weld SE Bootstrap API is really powerful and allows to minimize the set of classes to be processed by the CDI container. As a result, the tests are fast and lightweight!
Comments