问题描述
我正在尝试使用以下堆栈进行集成测试:
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
我已经设置了与Arquillian的基本集成测试(已完成此处),并且我能够注入依赖关系,但注入 EntityManager
却是一个挑战.取消引用实体管理器字段始终会导致 NullPointerException
.
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.
请在下面查看我的 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
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));
}
}
Complete Maven project available on GitHub.
请问我在做错什么吗?
推荐答案
如@Soloviev Dmitry所述,您将CDI容器用于集成测试,该容器仅启用CDI.
As stated by @Soloviev Dmitry, you use a CDI container for your integration test, which only enables CDI.
我看到两种选择:
第一个是使用在您的maven项目中配置的Wildfly嵌入式容器,因此在maven阶段运行集成测试时,将下载wildfly并将您的测试包部署到该容器中.因此,使用ExampleDS可以很好地解决问题,因为Wildfly可以立即使用.
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.
有关详情,请参见这篇文章
第二个包括不使用Arquillian进行集成测试.因此,如果您的集成测试仅涵盖托管Bean(而不是会话Bean,Wildfly特定资源等),则可以在执行测试之前实例化一个CDI容器(例如,在使用Junit的@Before或@BeforeClass注释方法中).然后使用EntityManagerFactory类实例化EntityManager,并引用用于此集成测试的持久性单元.使用这种方法,您还可以创建CDI生产者,以便根据测试范围为集成测试(模拟)注入其他资源.
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依赖
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 ...
}
}
我通常选择集成测试的第二个解决方案,因为它比Arquillian测试更容易设置,并且执行速度更快.
I usually opt for second solution for Integration tests, because it's easier to setup than Arquillian tests, and faster to execute.
这篇关于无法使用Arquillian和WildFly在JPA集成测试中注入EntityManager的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!