Kohei Nozaki's blog 

ArquillianチュートリアルのJPAを使ったテストを走らせるところをやってみる


Posted on Saturday Jan 25, 2014 at 02:29PM in Technology


Arquillianチュートリアルのリモートコンテナでテストを走らせるところをやってみるの続きです。JPAを使ったテストを走らせるところをやってみます。今回も基本的にはチュートリアル[1]なぞるだけです。

環境

  • JBoss AS 7.1.1.Final
  • Eclipse Kepler SR1
  • Apache Maven 2.2.1 (r801777; 2009-08-07 04:16:01+0900)
  • Apple JDK6u65
  • OS X 10.9.1

準備

チュートリアルにはGlassFishでテストを走らせる方法についても書いてありますが、ここではJBossで必要なものだけ用意します

何を作るか

この画像で選択されている4つのリソースを作ります

Game.java (エンティティクラス)

package org.arquillian.example;

import java.io.Serializable;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;

@Entity
public class Game implements Serializable {
    private Long id;
    private String title;

    public Game() {}

    public Game(String title) {
        this.title = title;
    }

    @Id @GeneratedValue
    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    @NotNull
    @Size(min = 3, max = 50)
    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    @Override
    public String toString() {
        return "Game@" + hashCode() + "[id = " + id + "; title = " + title + "]";
    }
}

GamePersistenceTest.java (テストクラス)

このチュートリアルではEntityManagerを叩いているのはこのテストクラスだけです。本当はJPAを使ったEJBのテストをしたいところですが、とりあえずこれでやってみます

package org.arquillian.example;

import java.util.List;
import javax.inject.Inject;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.transaction.UserTransaction;
import org.junit.Before;
import org.junit.After;
import org.junit.Test;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import org.junit.Assert;
import org.jboss.arquillian.container.test.api.Deployment;
import org.jboss.arquillian.junit.Arquillian;
import org.jboss.shrinkwrap.api.Archive;
import org.jboss.shrinkwrap.api.ShrinkWrap;
import org.jboss.shrinkwrap.api.asset.EmptyAsset;
import org.jboss.shrinkwrap.api.spec.WebArchive;
import org.junit.runner.RunWith;

@RunWith(Arquillian.class)
public class GamePersistenceTest {
    @Deployment
    public static Archive<?> createDeployment() {
        return ShrinkWrap.create(WebArchive.class, "test.war")
            .addPackage(Game.class.getPackage())
            .addAsResource("test-persistence.xml", "META-INF/persistence.xml")
            .addAsWebInfResource(EmptyAsset.INSTANCE, "beans.xml")
            .addAsWebInfResource("jbossas-ds.xml");
    }

    private static final String[] GAME_TITLES = {
        "Super Mario Brothers",
        "Mario Kart",
        "F-Zero"
    };

    @PersistenceContext
    EntityManager em;

    @Inject
    UserTransaction utx;

    @Before
    public void preparePersistenceTest() throws Exception {
        clearData();
        insertData();
        startTransaction();
    }

    private void clearData() throws Exception {
        utx.begin();
        em.joinTransaction();
        System.out.println("Dumping old records...");
        em.createQuery("delete from Game").executeUpdate();
        utx.commit();
    }

    private void insertData() throws Exception {
        utx.begin();
        em.joinTransaction();
        System.out.println("Inserting records...");
        for (String title : GAME_TITLES) {
            Game game = new Game(title);
            em.persist(game);
        }
        utx.commit();
        // clear the persistence context (first-level cache)
        em.clear();
    }

    private void startTransaction() throws Exception {
        utx.begin();
        em.joinTransaction();
    }

    @After
    public void commitTransaction() throws Exception {
        utx.commit();
    }

    @Test
    public void shouldFindAllGamesUsingJpqlQuery() throws Exception {
        // given
        String fetchingAllGamesInJpql = "select g from Game g order by g.id";

        // when
        System.out.println("Selecting (using JPQL)...");
        List<Game> games = em.createQuery(fetchingAllGamesInJpql, Game.class).getResultList();

        // then
        System.out.println("Found " + games.size() + " games (using JPQL):");
        assertContainsAllGames(games);
    }

    private static void assertContainsAllGames(Collection<Game> retrievedGames) {
        Assert.assertEquals(GAME_TITLES.length, retrievedGames.size());
        final Set<String> retrievedGameTitles = new HashSet<String>();
        for (Game game : retrievedGames) {
            System.out.println("* " + game);
            retrievedGameTitles.add(game.getTitle());
        }
        Assert.assertTrue(retrievedGameTitles.containsAll(Arrays.asList(GAME_TITLES)));
    }
}

jbossas-ds.xml (データソース定義)

データソース定義をこのファイルに書いておけば、テスト実行する度に一時的にデータソース定義を行ってくれます。APサーバ側のコンソールをいじってデータソース定義をやる必要はありません。これは便利。

本当はPostgreSQLあたりを使ってリアルにレコードを確認したいところですが、簡単のためとりあえずチュートリアル通りに標準搭載のH2を使ってインメモリデータベースを使います

<?xml version="1.0" encoding="UTF-8"?>
<datasources xmlns="http://www.jboss.org/ironjacamar/schema"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="
        http://www.jboss.org/ironjacamar/schema
        http://docs.jboss.org/ironjacamar/schema/datasources_1_0.xsd">
    <datasource enabled="true"
        jndi-name="jdbc/arquillian"
        pool-name="ArquillianEmbeddedH2Pool">
        <connection-url>jdbc:h2:mem:arquillian;DB_CLOSE_DELAY=-1</connection-url>
        <driver>h2</driver>
    </datasource>
</datasources>

test-persistence.xml (永続化コンテキスト定義)

JTAトランザクションのJavaEEなJPAの定義ですね。JavaSEのと違ってエンティティクラス名の列挙は必要ありません。良い。

<?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">
        <jta-data-source>jdbc/arquillian</jta-data-source>
        <properties>
            <property name="hibernate.hbm2ddl.auto" value="create-drop"/>
            <property name="hibernate.show_sql" value="true"/>
        </properties>
    </persistence-unit>
</persistence>

テスト実行

  • 前回同様、右クリック→Run As→JUnit Test
  • Profileも前回同様JBossのremoteで

JUnit窓

ログ

16:22:40,034 INFO  [org.jboss.as.repository] (management-handler-thread - 17) JBAS014900: Content added at location /Users/kyle/apps/jboss-as-7.1.1.Final/standalone/data/content/48/93a135faeb37e43d3d9346ea59cc2bfc3c784c/content
16:22:40,040 INFO  [org.jboss.as.server.deployment] (MSC service thread 1-5) JBAS015876: Starting deployment of "arquillian-service"
16:22:40,100 WARN  [org.jboss.as.dependency.private] (MSC service thread 1-5) JBAS018567: Deployment "deployment.arquillian-service" is using a private module ("org.jboss.as.jmx:main") which may be changed or removed in future versions without notice.
16:22:40,101 WARN  [org.jboss.as.dependency.private] (MSC service thread 1-5) JBAS018567: Deployment "deployment.arquillian-service" is using a private module ("org.jboss.as.server:main") which may be changed or removed in future versions without notice.
16:22:40,101 WARN  [org.jboss.as.dependency.private] (MSC service thread 1-5) JBAS018567: Deployment "deployment.arquillian-service" is using a private module ("org.jboss.as.osgi:main") which may be changed or removed in future versions without notice.
16:22:40,102 WARN  [org.jboss.as.dependency.private] (MSC service thread 1-5) JBAS018567: Deployment "deployment.arquillian-service" is using a private module ("org.jboss.jandex:main") which may be changed or removed in future versions without notice.
16:22:40,102 WARN  [org.jboss.as.dependency.private] (MSC service thread 1-5) JBAS018567: Deployment "deployment.arquillian-service" is using a private module ("org.jboss.osgi.framework:main") which may be changed or removed in future versions without notice.
16:22:40,123 INFO  [org.jboss.as.server] (management-handler-thread - 17) JBAS018559: Deployed "arquillian-service"
16:22:40,251 INFO  [org.jboss.as.repository] (management-handler-thread - 18) JBAS014900: Content added at location /Users/kyle/apps/jboss-as-7.1.1.Final/standalone/data/content/ed/a8915f6ceb2f30ae6c44b37a827c3c0064d992/content
16:22:40,253 INFO  [org.jboss.as.server.deployment] (MSC service thread 1-4) JBAS015876: Starting deployment of "test.war"
16:22:40,307 INFO  [org.jboss.as.jpa] (MSC service thread 1-2) JBAS011401: Read persistence.xml for test
16:22:40,350 INFO  [org.jboss.weld.deployer] (MSC service thread 1-7) JBAS016002: Processing weld deployment test.war
16:22:40,387 INFO  [org.jboss.weld.deployer] (MSC service thread 1-15) JBAS016005: Starting Services for CDI deployment: test.war
16:22:40,401 INFO  [org.jboss.as.arquillian] (MSC service thread 1-9) Arquillian deployment detected: ArquillianConfig[service=jboss.arquillian.config."test.war",unit=test.war,tests=[org.arquillian.example.GreeterTest, org.arquillian.example.GamePersistenceTest]]
16:22:40,402 INFO  [org.jboss.as.connector.subsystems.datasources] (MSC service thread 1-2) JBAS010400: Bound data source [jdbc/arquillian]
16:22:40,403 INFO  [org.jboss.as.jpa] (MSC service thread 1-2) JBAS011402: Starting Persistence Unit Service 'test.war#test'
16:22:40,498 INFO  [org.hibernate.annotations.common.Version] (MSC service thread 1-2) HCANN000001: Hibernate Commons Annotations {4.0.1.Final}
16:22:40,503 INFO  [org.hibernate.Version] (MSC service thread 1-2) HHH000412: Hibernate Core {4.0.1.Final}
16:22:40,505 INFO  [org.hibernate.cfg.Environment] (MSC service thread 1-2) HHH000206: hibernate.properties not found
16:22:40,506 INFO  [org.hibernate.cfg.Environment] (MSC service thread 1-2) HHH000021: Bytecode provider name : javassist
16:22:40,525 INFO  [org.hibernate.ejb.Ejb3Configuration] (MSC service thread 1-2) HHH000204: Processing PersistenceUnitInfo [
    name: test
    ...]
16:22:40,648 INFO  [org.hibernate.service.jdbc.connections.internal.ConnectionProviderInitiator] (MSC service thread 1-2) HHH000130: Instantiating explicit connection provider: org.hibernate.ejb.connection.InjectedDataSourceConnectionProvider
16:22:40,830 INFO  [org.hibernate.dialect.Dialect] (MSC service thread 1-2) HHH000400: Using dialect: org.hibernate.dialect.H2Dialect
16:22:40,835 WARN  [org.hibernate.dialect.H2Dialect] (MSC service thread 1-2) HHH000431: Unable to determine H2 database version, certain features may not work
16:22:40,838 INFO  [org.hibernate.engine.jdbc.internal.LobCreatorBuilder] (MSC service thread 1-2) HHH000423: Disabling contextual LOB creation as JDBC driver reported JDBC version [3] less than 4
16:22:40,845 INFO  [org.hibernate.engine.transaction.internal.TransactionFactoryInitiator] (MSC service thread 1-2) HHH000268: Transaction strategy: org.hibernate.engine.transaction.internal.jta.CMTTransactionFactory
16:22:40,848 INFO  [org.hibernate.hql.internal.ast.ASTQueryTranslatorFactory] (MSC service thread 1-2) HHH000397: Using ASTQueryTranslatorFactory
16:22:40,875 INFO  [org.hibernate.validator.util.Version] (MSC service thread 1-2) Hibernate Validator 4.2.0.Final
16:22:41,079 INFO  [org.hibernate.tool.hbm2ddl.SchemaExport] (MSC service thread 1-2) HHH000227: Running hbm2ddl schema export
16:22:41,083 INFO  [stdout] (MSC service thread 1-2) Hibernate: drop table Game if exists
16:22:41,083 INFO  [stdout] (MSC service thread 1-2) Hibernate: drop sequence hibernate_sequence
16:22:41,090 ERROR [org.hibernate.tool.hbm2ddl.SchemaExport] (MSC service thread 1-2) HHH000389: Unsuccessful: drop sequence hibernate_sequence
16:22:41,090 ERROR [org.hibernate.tool.hbm2ddl.SchemaExport] (MSC service thread 1-2) シーケンス "HIBERNATE_SEQUENCE" が見つかりません
Sequence "HIBERNATE_SEQUENCE" not found; SQL statement:
drop sequence hibernate_sequence [90036-161]
16:22:41,090 INFO  [stdout] (MSC service thread 1-2) Hibernate: create table Game (id bigint not null, title varchar(50) not null, primary key (id))
16:22:41,091 INFO  [stdout] (MSC service thread 1-2) Hibernate: create sequence hibernate_sequence start with 1 increment by 1
16:22:41,093 INFO  [org.hibernate.tool.hbm2ddl.SchemaExport] (MSC service thread 1-2) HHH000230: Schema export complete
16:22:41,113 INFO  [org.jboss.weld.deployer] (MSC service thread 1-7) JBAS016008: Starting weld service for deployment test.war
16:22:41,239 INFO  [org.jboss.web] (MSC service thread 1-6) JBAS018210: Registering web context: /test
16:22:41,248 INFO  [org.jboss.as.server] (management-handler-thread - 18) JBAS018559: Deployed "test.war"
16:22:41,407 INFO  [stdout] (pool-4-thread-4) Dumping old records...
16:22:41,501 INFO  [stdout] (pool-4-thread-4) Hibernate: delete from Game
16:22:41,515 INFO  [stdout] (pool-4-thread-4) Inserting records...
16:22:41,517 INFO  [stdout] (pool-4-thread-4) Hibernate: call next value for hibernate_sequence
16:22:41,549 INFO  [stdout] (pool-4-thread-4) Hibernate: call next value for hibernate_sequence
16:22:41,550 INFO  [stdout] (pool-4-thread-4) Hibernate: call next value for hibernate_sequence
16:22:41,566 INFO  [stdout] (pool-4-thread-4) Hibernate: insert into Game (title, id) values (?, ?)
16:22:41,568 INFO  [stdout] (pool-4-thread-4) Hibernate: insert into Game (title, id) values (?, ?)
16:22:41,569 INFO  [stdout] (pool-4-thread-4) Hibernate: insert into Game (title, id) values (?, ?)
16:22:41,573 INFO  [stdout] (pool-4-thread-4) Selecting (using JPQL)...
16:22:41,584 INFO  [stdout] (pool-4-thread-4) Hibernate: select game0_.id as id0_, game0_.title as title0_ from Game game0_ order by game0_.id
16:22:41,588 INFO  [stdout] (pool-4-thread-4) Found 3 games (using JPQL):
16:22:41,588 INFO  [stdout] (pool-4-thread-4) * Game@1954523691[id = 1; title = Super Mario Brothers]
16:22:41,589 INFO  [stdout] (pool-4-thread-4) * Game@402776278[id = 2; title = Mario Kart]
16:22:41,589 INFO  [stdout] (pool-4-thread-4) * Game@592449002[id = 3; title = F-Zero]
16:22:41,641 INFO  [org.jboss.weld.deployer] (MSC service thread 1-14) JBAS016009: Stopping weld service for deployment test.war
16:22:41,643 INFO  [org.jboss.as.jpa] (MSC service thread 1-14) JBAS011403: Stopping Persistence Unit Service 'test.war#test'
16:22:41,643 INFO  [org.hibernate.tool.hbm2ddl.SchemaExport] (MSC service thread 1-14) HHH000227: Running hbm2ddl schema export
16:22:41,644 INFO  [stdout] (MSC service thread 1-14) Hibernate: drop table Game if exists
16:22:41,647 INFO  [stdout] (MSC service thread 1-14) Hibernate: drop sequence hibernate_sequence
16:22:41,647 INFO  [org.hibernate.tool.hbm2ddl.SchemaExport] (MSC service thread 1-14) HHH000230: Schema export complete
16:22:41,648 INFO  [org.jboss.as.connector.subsystems.datasources] (MSC service thread 1-8) JBAS010409: Unbound data source [jdbc/arquillian]
16:22:41,656 INFO  [org.jboss.as.server.deployment] (MSC service thread 1-9) JBAS015877: Stopped deployment test.war in 40ms
16:22:41,664 INFO  [org.jboss.as.repository] (management-handler-thread - 20) JBAS014901: Content removed from location /Users/kyle/apps/jboss-as-7.1.1.Final/standalone/data/content/ed/a8915f6ceb2f30ae6c44b37a827c3c0064d992/content
16:22:41,665 INFO  [org.jboss.as.server] (management-handler-thread - 20) JBAS018558: Undeployed "test.war"
16:22:41,685 INFO  [org.jboss.as.server.deployment] (MSC service thread 1-11) JBAS015877: Stopped deployment arquillian-service in 5ms
16:22:41,693 INFO  [org.jboss.as.repository] (management-handler-thread - 17) JBAS014901: Content removed from location /Users/kyle/apps/jboss-as-7.1.1.Final/standalone/data/content/48/93a135faeb37e43d3d9346ea59cc2bfc3c784c/content
16:22:41,693 INFO  [org.jboss.as.server] (management-handler-thread - 17) JBAS018558: Undeployed "arquillian-service"

備考

特に問題なさげですね。しかも速い。クラスの数も少なくアプリケーションアーカイブのサイズも小さいので当然かもしれませんが3〜4秒です。これならJPAのマニアックな機能を使った複雑な機能の実装とテストも怖くないですね。

というか本家のチュートリアル[1]がよくできてて日本語訳も読みやすいので読みましょう。

ちなみにチュートリアルにも書かれていますが埋め込みモードではJPAを使ったテストは動かないそうです。ただし埋め込みGlassFishは可。

続き

ArquillianをWildFly8.0.0.CR1で動かしてみる

参考文献

  1. Testing Java Persistence · Arquillian Guides



No one has commented yet.

Leave a Comment

HTML Syntax: NOT allowed