使用Arquillian和WildFly无法在JPA集成测试中注入EntityManager

时间:2015-06-17 11:56:56

标签: maven jpa integration-testing wildfly jboss-arquillian

我正在尝试使用以下堆栈进行集成测试:

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

我已经使用Arquillian设置了基本的集成测试(完成here)并且我能够注入依赖项,但注入EntityManager证明是一个挑战。取消引用实体管理器字段始终会生成NullPointerException

我看过很多文章(包括thisthis),但我仍然无法让这个看似简单的事情发挥作用。

请参阅下面的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>

测试的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>

测试用例

@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));
  }
}

完整的Maven项目on GitHub

请问我做错了什么?

4 个答案:

答案 0 :(得分:1)

只是不使用焊接,罪孽数据源超出了CI和DI可能涵盖的范围。可能你可以用Mokito嘲笑它,并保持光焊接,

<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>

但是如果你想处理真正的数据库使用托管jboss(ExampleDS是一个演示jboss h2数据源)或管理glassfish而不是。

        <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

答案 1 :(得分:1)

如@Soloviev Dmitry所述,您使用CDI容器进行集成测试,该测试仅启用CDI。

我看到两个选项:

第一个是使用在maven项目中配置的wildfly嵌入式容器,因此在maven阶段运行集成测试时,将下载wildfly并将测试包部署到它。因此,使用ExampleDS,它可以正常工作,因为Wildfly开箱即用。

有关详细信息,请参阅this post

第二个将包括不使用Arquillian进行集成测试。因此,如果您的集成测试仅涵盖托管bean(不是会话bean,Wildfly特定资源,......),您可以在测试执行之前实例化CDI容器(例如,使用Junit在@Before或@BeforeClass注释方法中)然后使用EntityManagerFactory类实例化您的EntityManager,引用用于此集成测试的持久性单元。使用此方法,您还可以创建CDI生成器,以便为集成测试注入其他资源,模拟,具体取决于测试的范围。

maven依赖

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

测试类

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 ...
    }

}

我通常选择第二个集成测试解决方案,因为它比Arquillian测试更容易设置,并且执行起来更快。

答案 2 :(得分:0)

使用应用程序管理的实体管理器。

@PersistenceUnit
EntityManagerFactory emf; 

使用

创建entityManager
EntityManager em = emf.createEntityManager();

创建容器管理实体管理器并由容器本身注入。如果您不在服务器环境中,则需要使用 application managed persistence context

答案 3 :(得分:0)

我猜您的上下文文件中缺少事务管理器+实体管理器工厂。在test-persistence.xml中配置两者,然后使实体管理器工厂成为事务管理器的属性。