如何使用不同的数据源来播种/清理数据库并运行测试?

时间:2017-06-06 10:47:07

标签: java jboss-arquillian

我们正在尝试为我们的项目设置Arquillian以运行自动测试。我们想利用arquillian持久性扩展来使用persistance层编写测试。因此,我们希望使用@UsingDataSet和/或@CreateSchema@注释来为数据库设定种子。

我们所有的应用程序组件都拥有自己的数据库用户,这些用户只能访问组件所需的那些表/属性。没有组件有权执行delete或DDL语句。所以我们需要在测试之前/之后切换数据库用户/数据源种子/清理模式,并执行这样的测试:

  1. 种子数据库,使用datasaource A删除并重新创建序列
  2. 使用数据源B
  3. 运行测试
  4. 使用数据源A清理数据库
  5. 显而易见的是,如果我们将组件数据库用户所需的删除/ DDL权限授予arquillian测试,则每次定义测试结果都不可靠。

    那么我们如何使用arquillian.xml中定义的不同数据源来播种/清理数据库并运行测试呢?

2 个答案:

答案 0 :(得分:2)

我访问过的arquillian培训课程的讲师提到,为播种/清理以及EJB的PersistenceContext定义不同的数据源应该没有问题。所以我坐下来测试一下。

  

TL; DR:可以使用两个不同的数据源。

以下是我的测试设置和测试结果。

本地测试设置

数据库

作为数据库,我在我公司使用Oracle数据库时安装了Oracle XE。由于组件的数据库用户没有自己的架构但访问架构所有者的表,因此我创建了三个数据库用户:

  • 用户" bish"是架构的架构所有者" bish"其中包含表" Emp"我在测试中使用
  • 用户"阅读用户"得到了" SELECT,INSERT,UPDATE"表格的特权" bish.Emp"
  • 用户" writinguser"得到了" SELECT,INSERT,UPDATE,DELETE"表格的特权" bish.Emp"

应用程序服务器

作为一个应用程序服务器,我使用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