Unable to Inject EntityManager in JPA Integration Testing With Arquillian and WildFly

4.5k views Asked by At

I'm trying do integration testing with the following stack:

App server: Embedded WildFly
CDI container: Weld
Database: In-memory H2
ORM: Hibernate/JPA
Platform: Java 8
OS: Mac OS X 10.10

I've setup basic integration testing with Arquillian (as done here) and I'm able to inject dependencies but injecting EntityManager proves to be a challenge. Dereferencing the entity manager field always results in a NullPointerException.

I've seen many articles (including this and this) but I'm still not able to get this seemingly simple thing to work.

Please see below my pom.xml

  <dependencies>
    <dependency>
      <groupId>org.jboss.spec</groupId>
      <artifactId>jboss-javaee-7.0</artifactId>
      <version>1.0.0.Final</version>
      <type>pom</type>
      <scope>provided</scope>
    </dependency>

    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.8.1</version>
      <scope>test</scope>
    </dependency>

    <!-- JUnit Container Implementation for the Arquillian Project -->
    <dependency>
      <groupId>org.jboss.arquillian.junit</groupId>
      <artifactId>arquillian-junit-container</artifactId>
      <scope>test</scope>
    </dependency>

    <dependency>
      <groupId>org.jboss.arquillian.protocol</groupId>
      <artifactId>arquillian-protocol-servlet</artifactId>
      <scope>test</scope>
    </dependency>

    <dependency>
      <groupId>org.jboss.arquillian.container</groupId>
      <artifactId>arquillian-weld-ee-embedded-1.1</artifactId>
      <version>1.0.0.CR3</version>
      <scope>test</scope>
    </dependency>

    <dependency>
      <groupId>org.jboss.arquillian.extension</groupId>
      <artifactId>arquillian-persistence-dbunit</artifactId>
      <version>1.0.0.Alpha7</version>
      <scope>test</scope>
    </dependency>

    <dependency>
      <groupId>org.jboss.weld</groupId>
      <artifactId>weld-core</artifactId>
      <version>1.1.5.Final</version>
      <scope>test</scope>
    </dependency>

    <dependency>
      <groupId>org.slf4j</groupId>
      <artifactId>slf4j-simple</artifactId>
      <version>1.6.4</version>
      <scope>test</scope>
    </dependency>
  </dependencies>

  <dependencyManagement>
    <dependencies>
      <dependency>
        <groupId>org.jboss.arquillian</groupId>
        <artifactId>arquillian-bom</artifactId>
        <version>1.1.8.Final</version>
        <scope>import</scope>
        <type>pom</type>
      </dependency>
    </dependencies>
  </dependencyManagement>

test-persistence.xml

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0" xmlns="http://java.sun.com/xml/ns/persistence"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="
        http://java.sun.com/xml/ns/persistence
        http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
  <persistence-unit name="test" transaction-type="JTA">
    <provider>org.hibernate.ejb.HibernatePersistence</provider>
    <class>com.xyz.hellomaven.DummyEntity</class>

    <jta-data-source>java:jboss/datasources/ExampleDS</jta-data-source>
    <!--<jta-data-source>java:/DefaultDS</jta-data-source>-->
    <!--<jta-data-source>jdbc/arquillian</jta-data-source>-->

    <properties>
      <property name="hibernate.show_sql" value="true" />
      <property name="hibernate.hbm2ddl.auto" value="update"/>
      <!--<property name="hibernate.dialect" value="org.hibernate.dialect.H2Dialect" />-->
    </properties>
  </persistence-unit>
</persistence>

Test case

@RunWith(Arquillian.class)
public class GreeterTest {

  @Inject
  private Greeter instance; // Injection works!

  @PersistenceContext
  private EntityManager em; // Null pointer.

  public GreeterTest() {
  }

  @Deployment
  public static WebArchive createDeployment() {
    return ShrinkWrap.create(WebArchive.class)
        .addClasses(Greeter.class, PhraseBuilder.class, DummyInterceptor.class)
        .addAsResource("logging.properties", "META-INF/logging.properties")
        .addAsResource("test-persistence.xml", "META-INF/persistence.xml")
        .addAsWebInfResource(EmptyAsset.INSTANCE, "beans.xml");
  }

  @Test
  public void testCreateGreeting() {
    System.out.println("createGreeting");
    assertEquals("Hello, Steve!", instance.createGreeting("Steve"));
  }

  @Test
  public void testPersistence() {
    DummyEntity de = new DummyEntity();
    de.setId(1l);
    de.setName("Petr Cech");
    de.setAge(10);
    em.persist(de);

    Query q = em.createQuery("SELECT d.age FROM DummyEntity d");
    assertEquals(10, q.getResultList().get(0));
  }
}

Complete Maven project available on GitHub.

Please what am I doing wrong?

4

There are 4 answers

1
Prasad Kharkar On

Use the application managed entitymanager.

@PersistenceUnit
EntityManagerFactory emf; 

and create entityManager using

EntityManager em = emf.createEntityManager();

a container managed entitymanager is created and injected by container itself. If you are not under a server environment, then you need to use application managed persistence context.

1
Marcus Biel On

I guess the transaction manager + Entity Manger Factory are missing in your context file. Configure both in test-persistence.xml, then make the entity manager factory a property of the transaction manager.

0
Soloviev Dmitry On

just don't use weld, sins data-sources is out of things that could be covered by CI and DI. probably you may mock it with Mokito and stay with light Weld,

<dependency>
      <groupId>org.jboss.arquillian.container</groupId>
      <artifactId>arquillian-weld-ee-embedded-1.1</artifactId>
      <version>1.0.0.CR3</version>
      <scope>test</scope>
</dependency>

But if you want to deal with real DB use managed jboss (ExampleDS is a demo jboss h2 datasource) or managed glassfish instead.

        <dependency>
            <groupId>org.jboss.as</groupId>
            <artifactId>jboss-as-arquillian-container-managed</artifactId>
            <version>7.1.1.Final</version>
            <scope>test</scope>
        </dependency>

ref. https://github.com/arquillian/arquillian-examples/blob/master/arquillian-persistence-tutorial/pom.xml

0
Rémi Bantos On

As stated by @Soloviev Dmitry, you use a CDI container for your integration test, which only enables CDI.

There are two options I see:

First one is to use a wildfly-embedded container configured in your maven project, so during maven phase running your integration-tests, wildfly will be downloaded and your test package will be deployed to it. So with ExampleDS it would work fine, as it comes with Wildfly out of the box.

See this post for details

Second one would consist in not using Arquillian for your integration test. So if your integration test only covers managed beans, (not session beans, Wildfly specific resources, ...), you could just instantiate a CDI container prior to your test execution (in @Before or @BeforeClass annotated method using Junit for example) and then instantiate your EntityManager by using the EntityManagerFactory class, referencing your persistence unit used for this integration test. With this method, you could also create CDI producers to inject other resources for your integration test, mocks, depending on the scope of your test.

maven dependency

<dependency>
    <groupId>org.jboss.weld.se</groupId>
    <artifactId>weld-se</artifactId>
    <version>2.1.2.Final</version>
    <scope>test</scope>
</dependency>

The test class

import org.jboss.weld.environment.se.Weld;
import org.jboss.weld.environment.se.WeldContainer;
import org.junit.*;

public class ExampleIT {

    private EntityManager em;

    protected static Weld weld;
    protected static WeldContainer container;

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

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

    @Before
    private void before(){
    em = Persistence.createEntityManagerFactory("MyPersistenceUnit").createEntityManager();
    }

    @Test
    public void testToto(){
        // Do something with entity manager ...
    }

}

I usually opt for second solution for Integration tests, because it's easier to setup than Arquillian tests, and faster to execute.