无法在使用 Arquillian 和 WildFly 的 JPA 集成测试中注入 EntityManager
Posted
技术标签:
【中文标题】无法在使用 Arquillian 和 WildFly 的 JPA 集成测试中注入 EntityManager【英文标题】:Unable to Inject EntityManager in JPA Integration Testing With Arquillian and WildFly 【发布时间】:2015-09-02 15:32:12 【问题描述】:我正在尝试使用以下堆栈进行集成测试:
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
。
我看过很多文章(包括this 和this),但我仍然无法让这个看似简单的事情发挥作用。
请看下面我的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>
测试用例
@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。
请问我做错了什么?
【问题讨论】:
我不了解 Arquillian,但容器管理的 entitymagner 仅在服务器上可用。我相信您将不得不使用应用程序托管实体管理器。 这有两个问题。 1. 行不通。如果您无法注入 EM,您将无法注入 EMF(如果我错了,请纠正我)。 2. 即使它确实有效,这也让我的“集成测试”变得不那么可靠,因为架构不再与生产环境相同(容器与 bean 管理的持久性/事务) Arquillian 是一个集成测试环境,并且是预计将生产支持服务器组件。这与仅在 JUnit/TestNG 中工作不同,后者将是类似 SE 的应用程序。 【参考方案1】:只是不要使用焊接,sins 数据源超出了 CI 和 DI 可能涵盖的范围。也许你可以用 Mokito 嘲笑它,并留在 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>
但是,如果您想处理真正的数据库,请改用托管 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>
参考。 https://github.com/arquillian/arquillian-examples/blob/master/arquillian-persistence-tutorial/pom.xml
【讨论】:
【参考方案2】:正如@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 测试更容易设置,并且执行速度更快。
【讨论】:
【参考方案3】:使用应用程序管理的实体管理器。
@PersistenceUnit
EntityManagerFactory emf;
并使用
创建 entityManagerEntityManager em = emf.createEntityManager();
容器管理的 entitymanager 由容器自身创建和注入。如果你不是在服务器环境下,那么你需要使用 application managed persistence context。
【讨论】:
您好,感谢您花时间帮助我。我只是尝试了这种方法(只是为了确定),不出所料,它没有用。这有两个问题。 1. 行不通。如果您无法注入 EM,您将无法注入 EMF(如果我错了,请纠正我)。 2. 即使它确实有效,它也让我的“集成测试”变得不那么可靠,因为架构不再与生产环境相同(容器与 bean 管理的持久性/事务) Arquillian 是一个集成测试环境,并且是预计将生产支持服务器组件。【参考方案4】:我猜您的上下文文件中缺少事务管理器 + 实体管理器工厂。在 test-persistence.xml 中配置两者,然后将实体管理器工厂设置为事务管理器的属性。
【讨论】:
嗨,Marcus,感谢您抽出时间帮我解答。您能否提供示例 sn-ps 来实施您的解决方案?提前致谢。以上是关于无法在使用 Arquillian 和 WildFly 的 JPA 集成测试中注入 EntityManager的主要内容,如果未能解决你的问题,请参考以下文章
无法创建类 org.jboss.arquillian.test.impl.EventTestRunnerAdaptor 的新实例