使用 arquilian 测试时何时构建数据库结构?

When to build the DB structure when testing with arquilian?

我从集成测试和 Arquilian 开始。我对这个工具非常满意。 我几乎已经准备好了所有东西,除了一件事:

我的数据库结构在整个测试套件中当然是稳定的,因此,为了将测试所需的时间减少到 运行,我希望尽可能少地构建数据库并让每个测试填充数据库,处理并清理它。

我想在测试套件的开头构建数据库并让所有测试 fill/erase 数据库可能有点冒险:如果一个测试没有很好地清理,我可能会得到非可重现的测试。

但也许在每次测试时构建它 class 是一个很好的方法,如果测试有问题,它会更容易发现,因为范围较小。

我尝试使用@BeforeClass 和@AfterClass 来做到这一点,但是它们是在客户端上执行的并且也是静态的,所以我没有准备好用于连接到数据库的资源。

我在每次测试前创建数据库结构的方法是否正确? arquilian 生命周期的哪个阶段可以用来构建数据库?

您不必自己做,至少如果您在项目中使用 JPA 2.1 的话。考虑以下测试 class:

@RunWith(Arquillian.class)
public class MyTest {

    @Deployment
    public static WebArchive createDeployment() throws Exception {
        return ShrinkWrap.create(WebArchive.class)
            .addAsResource("META-INF/init-schema.sql")  // create table ...
            .addAsResource("META-INF/testdata.sql")  // insert into ...
            .addAsResource("META-INF/drop-schema.sql") // drop table ...
            .addAsResource("META-INF/persistence.xml");
            // and maybe more ...
    }

}

调用 createDeployment() 方法来创建 WAR 文件,该文件将部署到您的应用程序服务器。

您的 persistence.xml 应该引用那些 SQL 脚本:

[...]
<persistence-unit [...]>
    <properties>
        <property name="javax.persistence.schema-generation.database.action" value="drop-and-create" />
        <property name="javax.persistence.schema-generation.create-source" value="script" />
        <property name="javax.persistence.schema-generation.create-script-source" value="META-INF/init-schema.sql" />
        <property name="javax.persistence.schema-generation.drop-source" value="script" />
        <property name="javax.persistence.schema-generation.drop-script-source" value="META-INF/drop-schema.sql" />
        <property name="javax.persistence.sql-load-script-source" value="META-INF/testdata.sql" />
    </properties>
</persistence-unit>

这样,在部署测试WAR 时会自动设置数据库。确保 SQL 文件位于 "META-INF" 文件夹中(如果您使用的是 Maven,它位于 "src/test/resources/META-INF" 中)。

如果你想控制你的测试方法被执行的顺序,你可以使用@InSequence注解,例如:

public class MyTest {
    [...]

    private @Inject EntityManager entityManager

    @Test @InSequence(0)
    public void shouldHaveFoo() {
        Foo foo = entityManager.find(Foo.class, Long.valueOf(1));
        assertNotNull(foo);
    }

    @Test @InSequence(1)
    public void shouldHaveBar() {
        Bar bar = entityManager.find(Bar.class, Long.valueOf(99));
        assertNotNull(bar);
    }
}

使用 Arqullian 的事务扩展,效果很好 (http://arquillian.org/modules/transaction-extension/)。您在事务中创建的数据在测试完成后将被删除。

唯一的问题是数据库中的数据会影响您的测试。解决方案是针对空数据库进行测试。它可以是嵌入的、真实的或如上所述的方法。但是扩展程序可以正确管理所有事务管理,您不必关心任何事情。