我们正在尝试为我们的项目设置Arquillian以运行自动测试。我们想利用arquillian持久性扩展来使用persistance层编写测试。因此,我们希望使用@UsingDataSet
和/或@CreateSchema@
注释来为数据库设定种子。
我们所有的应用程序组件都拥有自己的数据库用户,这些用户只能访问组件所需的那些表/属性。没有组件有权执行delete或DDL语句。所以我们需要在测试之前/之后切换数据库用户/数据源种子/清理模式,并执行这样的测试:
显而易见的是,如果我们将组件数据库用户所需的删除/ DDL权限授予arquillian测试,则每次定义测试结果都不可靠。
那么我们如何使用arquillian.xml中定义的不同数据源来播种/清理数据库并运行测试呢?
答案 0 :(得分:2)
我访问过的arquillian培训课程的讲师提到,为播种/清理以及EJB的PersistenceContext
定义不同的数据源应该没有问题。所以我坐下来测试一下。
TL; DR:可以使用两个不同的数据源。
以下是我的测试设置和测试结果。
作为数据库,我在我公司使用Oracle数据库时安装了Oracle XE
。由于组件的数据库用户没有自己的架构但访问架构所有者的表,因此我创建了三个数据库用户:
作为一个应用程序服务器,我使用Wildfly 10.x
并定义了两个数据源,我的两个测试用户各一个
<datasource jndi-name="java:/ReadingDS" pool-name="ReadingDS" enabled="true">
<connection-url>jdbc:oracle:thin:@localhost:1521:xe</connection-url>
<driver>oracle</driver>
<pool>
<min-pool-size>1</min-pool-size>
<max-pool-size>5</max-pool-size>
<prefill>true</prefill>
</pool>
<security>
<user-name>readinguser</user-name>
<password>oracle</password>
</security>
</datasource>
<datasource jndi-name="java:/WritingDS" pool-name="WritingDS" enabled="true">
<connection-url>jdbc:oracle:thin:@localhost:1521:xe</connection-url>
<driver>oracle</driver>
<pool>
<min-pool-size>1</min-pool-size>
<max-pool-size>5</max-pool-size>
<prefill>true</prefill>
</pool>
<security>
<user-name>writingguser</user-name>
<password>oracle</password>
</security>
</datasource>
然后我用一个实体,EJB,persistence.xml,arquillian.xml,dataSet和测试类编写了一个小应用程序
实体(仅显示显式架构命名的表定义)
@Entity
@Table(name = "Emp", schema = "bish")
public class Emp implements Serializable {
// Straight forward entity...
}
EJB有两种选择和删除所有条目的方法
@Stateless
@Remote(IEmpService.class)
@LocalBean
public class EmpService implements IEmpService {
@PersistenceContext
private EntityManager em;
public void removeAllEmps() {
em.createQuery("DELETE FROM Emp").executeUpdate();
}
public List<Emp> getAllEmps() {
return em.createQuery("FROM Emp", Emp.class).getResultList();
}
}
persistence.xml中的持久性单元使用&#34; ReadingDS&#34;在EJB内部
<persistence-unit name="ReadingUnit" transaction-type="JTA">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<jta-data-source>java:/ReadingDS</jta-data-source>
<shared-cache-mode>NONE</shared-cache-mode>
</persistence-unit>
Arquillian.xml,定义使用&#34; WritingDS&#34;种子/清理表和模式定义
<extension qualifier="persistence">
<property name="defaultDataSeedStrategy">CLEAN_INSERT</property>
<property name="defaultCleanupStrategy">USED_ROWS_ONLY</property>
<property name="defaultDataSource">java:/WritingDS</property>
</extension>
<extension qualifier="persistence-dbunit">
<property name="schema">bish</property>
</extension>
数据集&#34; empBefore.xml&#34;用于测试类
<?xml version="1.0" encoding="UTF-8"?>
<dataset>
<EMP EMPNO="9998" ENAME="TEst" JOB="Eins" HIREDATE="1982-01-23" SAL="1300" DEPTNO="10"/>
<EMP EMPNO="9999" ENAME="Test" JOB="Zwei" MGR="9998" HIREDATE="1982-01-23" SAL="1300" DEPTNO="10"/>
</dataset>
测试类:
@RunWith(Arquillian.class)
public class DataSourceTest {
@Deployment
public static JavaArchive createDeployment() {
// ...
}
@EJB
EmpService testclass;
@Rule
public ExpectedException thrown = ExpectedException.none();
@UsingDataSet("empBefore.xml")
@Test
public void GetAllEmps() {
List<Emp> allEmps = testclass.getAllEmps();
Assert.assertEquals(2, allEmps.size());
}
@UsingDataSet("empBefore.xml")
@Test
public void DeleteAllEmps() {
thrown.expect(EJBException.class);
thrown.expectCause(CoreMatchers.isA(PersistenceException.class));
testclass.removeAllEmps();
}
}
我首先执行了GetAllEmps
测试方法,以查看表是否正确地使用DataSet
的数据以及EJB的select方法是否正常工作。在我第一次执行时,我得到以下异常。 (很抱歉发布了这么多文字,但这很重要,见下文!)
19:15:51,553 WARN [com.arjuna.ats.arjuna](默认任务-38)ARJUNA012140:不允许添加多个最后资源。试图添加LastResourceRecord(XAOnePhaseResource(LocalXAResourceImpl @ 666ebccc [connectionListener = 11852abe connectionManager = 3f58cd97 warned = false currentXid =&lt; formatId = 131077,gtrid_length = 29,bqual_length = 36,tx_uid = 0:ffffc0a80002:d99c90f:59971e1c:4c,node_name = 1,branch_uid = 0:ffffc0a80002:d99c90f:59971e1c:50,subordinatenodename = null,eis_name = java:/ ReadingDS&gt; productName = Oracle productVersion = Oracle Database 11g Express Edition版本11.2.0.2.0 - 64bit生产 jndiName = java:/ ReadingDS ])),但已经有LastResourceRecord(XAOnePhaseResource(LocalXAResourceImpl @ 6027d87b [connectionListener = 41a0034d connectionManager = 329cdd5f warned = false currentXid =&lt; formatId = 131077,gtrid_length = 29,bqual_length = 36,tx_uid = 0:ffffc0a80002:d99c90f:59971e1c:4c,node_name = 1,branch_uid = 0:ffffc0a80002:d99c90f:59971e1c:4e,subordinatenodename = null,eis_name = java:/ WritingDS&gt; productName = Oracle productVersion = Oracle Database 11g Express Edition版本11.2 .0.2.0 - 64 bit Production jndiName = java:/ WritingDS ]))
19:15:51,554 WARN [org.hibernate.engine.jdbc.spi.SqlExceptionHelper](默认任务-38)SQL错误:0,SQLState:null
19:15:51,554 ERROR [org.hibernate.engine.jdbc.spi.SqlExceptionHelper](默认任务-38)javax.resource.ResourceException:IJ000457:在managedConnectionReconnected()cl = org.jboss.jca中未选中throwable。 core.connectionmanager.listener.TxConnectionListener@11852abe [state = NORMAL managed connection=org.jboss.jca.adapters.jdbc.local.LocalManagedConnection@7fc47256 connection handles = 0 lastReturned = 1503076551554 lastValidated = 1503075869230 lastCheckedOut = 1503076551553 trackByTx = false pool = org .jboss.jca.core.connectionmanager.pool.strategy.OnePool @ 6893c4c mcp = SemaphoreConcurrentLinkedQueueManagedConnectionPool @ 61e62cb9 [pool = ReadingDS] xaResource = LocalXAResourceImpl @ 666ebccc [connectionListener = 11852abe connectionManager = 3f58cd97 warned = false currentXid = null productName = Oracle productVersion = Oracle Database 11g Express Edition 11.2.0.2.0版 - 64位生产jndiName = java:/ ReadingDS] txSync = null]
19:15:51,554 ERROR [org.jboss.as.ejb3.invocation](默认任务-38)WFLYEJB0034:EJB Invocation在组件EmpService上失败,方法为public java.util.List de.test.EmpService.getAllEmps( ):javax.ejb.EJBTransactionRolledbackException:org.hibernate.exception.GenericJDBCException:无法获取JDBC连接
感谢this SO-Question我可以通过在我的野生动物中设置以下系统功能来解决问题:
<system-properties>
<property name="com.arjuna.ats.arjuna.allowMultipleLastResources" value="true"/>
</system-properties>
关于此异常最重要的事情是wildfly尝试在异常文本中创建两个连接,每个连接一个用于每个数据源(请参阅突出显示的JNDI名称)。在设置系统属性之前,我通过删除@UsingDataSet
- 注释来验证。删除测试用例失败后因为断言(Assert.assertEquals(2, allEmps.size());
)失败,因为表中没有行 - 这表示没有为播种创建第二个连接。所以我创建了系统属性,使用了DataSet
并得到了一个绿色条。
第二个测试方法尝试删除集合中的所有条目,这些条目必须在异常中失败,因为readingDS
数据源后面的用户无权删除表中的行。这个测试也是成功的。完整的异常日志是:
javax.ejb.EJBTransactionRolledbackException:org.hibernate.exception.SQLGrammarException:无法执行语句
[...]
引起:javax.persistence.PersistenceException:org.hibernate.exception.SQLGrammarException:无法执行语句
[...]
... 187更多
引起:org.hibernate.exception.SQLGrammarException:无法执行语句
[...]
... 217更多
引起:java.sql.SQLSyntaxErrorException:ORA-01031:权限不足
[...]
...... 226更多
正如您所看到的,由于权限不足,删除语句失效
通过在arquillian.xml
和EJB的持久性单元内定义数据源,可以使用不同的数据源来播种/删除表。 Arquillian和应用程序服务器可以正确处理这些不同的数据源。
答案 1 :(得分:0)
目前尚不支持(我们正在努力),但在版本2.0.0(目前处于alpha阶段的maven中心)有一种解决方法,使用编程方式而不是声明方式(使用注释) 。您可以在此处查看示例https://github.com/arquillian/arquillian-extension-persistence/blob/2.0.0/arquillian-ape-sql/container/int-tests/src/test/java/org/arquillian/integration/ape/dsl/ApeDslIncontainerTest.java