開発者ブログ
ツール・ライブラリ » Pitalium(hifiveリグレッションテストライブラリ) » Pitalium サンプル » Pitaliumを使用したテストにデータベースのリセット・アサーションを組み込む

Pitaliumを使用したテストにデータベースのリセット・アサーションを組み込む

Last modified by kashi on 2016/12/02, 15:07

Seleniumを使用してWebアプリをテストする場合、ブラウザからの操作によってデータベースに保存されている値が変化してしまい、次のテストケースに影響を与えてしまうことがあります。Pitaliumを使用したテストケースにおいて、データベースのリセットや、操作後のデータベースアサーションについて、簡単に解説します。

データベースのリセット・アサーション

DBUnit

Javaからデータベースを操作するにはいくつかの方法があります。JDBCDriverから操作する、JPAやMyBatisといったORマッパーを経由する、など様々です。今回は DbUnit という、JUnit拡張を使用します。
DbUnitはデータベーステストをするため、以下の便利な特徴があります。

  • データベースのレコードをクリアする、用意したデータセットの中身を一括挿入する、などの初期操作やリセット操作
  • データベースのレコードを、用意したデータセットを使用してデータベース単位、テーブル単位でアサーション
  • データセットはエクセルファイルやCSV、XMLがサポートされ、データベースからのエクスポートも可能

業務用途では、特にエクセルファイルでの入出力がサポートされているのが便利です。

DBUnitを使用したテストケースの作成

概要

Pitaliumは複数ブラウザでの同時実行が可能なテストライブラリです。
静的ページへの複数アクセスでは特に問題となりませんが、データの登録・削除が発生するページでは
ブラウザがアクセスする順番によって表示される内容が変化してしまい、テストすることが難しくなります。

これを解消するには、テストするブラウザ毎にWebアプリを立ち上げる方法が挙げられます。
しかしPitaliumではブラウザ毎にアクセス先を変更することはサポートされていません。
ブラウザ毎の設定である capabilities.json に各ブラウザのアクセス先を記述することで
擬似的に、ブラウザ毎にそれぞれの接続先へアクセスすることが可能となります。

1.capabilities.jsonを変更する

まずは capabilities.json ファイルを修正します。
各ブラウザ毎に必要な情報は WebアプリのベースURLデータベースの接続文字列 です。
SeleniumのCapabilitiesは、platformやbrowserName、version以外は自由に記述できますので、
例えば次の様にします。

 種別  capabilitiesのキー  サンプル値
 WebアプリのベースURL  pitalium.baseUrl  http://localhost:18080
 データベースの接続文字列  pitalium.db.connectionString  jdbc:h2:tcp://localhost//test_0;user=sa;password=
capabilities.json
[
  {
   "platform": "WINDOWS",
   "browserName": "internet explorer",
   "pitalium.db.connectionString": "jdbc:h2:tcp://localhost/~/test_0;user=sa;password=",
   "pitalium.baseUrl": "http://localhost:18080/"
  },
  {
   "platform": "WINDOWS",
   "browserName": "chrome",
   "pitalium.db.connectionString": "jdbc:h2:tcp://localhost/~/test_1;user=sa;password=",
   "pitalium.baseUrl": "http://localhost:18081/"
  }
]

2.テストに使用するデータを用意する

本サンプルではDbUnitを利用してテストケース毎にデータベースのレコードを初期化します。
データをエクセルで作成する際は、次のフォーマットとなります。

  • エクセルのシート名をデータベースのテーブル名とする
  • エクセルの1列目をデータベースのカラム名とする
  • 2列目以降に実際のデータを記述する

本サンプルのデータベーススキーマイメージは次の通りです。

 テーブル名  カラム名  種別  
 USER      ユーザー情報のテーブル
   ID  INT  ユニークID
   NAME  VARCHAR  ユーザー名
   AGE  INT  年齢
   EMAIL  VARCHAR  メールアドレス
 ITEM      ユーザーが所有するアイテムのテーブル
   ID  INT  ユニークID
   NAME  VARCHAR  アイテム名
   USER_ID  INT  所有するユーザーのID

初期化データのエクセルは以下の様になります。

ユーザーテーブル:
init-data-excel-user.png

アイテムテーブル:
init-data-excel-item.png

3.初期化データを挿入する

JUnitテストの@Beforeを使用して、テストケースの初期化処理のタイミングでデータベースのレコードをリセットします。

DataSetの作成

データベースを初期化するにはまずエクセルファイルからDataSetを生成します。
DataSet(IDataSetインターフェース)はDbUnitのクラスの1つで、テーブルデータの集合を現します。
先に述べた通りDbUnitはいくつかのデータ形式を扱うことができ、データ形式ごとにIDataSetの実装クラスが存在します。
エクセルをDataSetとするには org.dbunit.dataset.excel.XlsDataSet を使用します。

InputStream in = getClass().getResourceAsStream("init_data.xlsx");
IDataSet dataSet = new XlsDataSet(in);

DatabaseConnectionの作成

次にDbUnitのデータベース接続クラスのDatabaseConnectionを生成します。
その際データベースの接続文字列が必要になりますので、capabilitiesから "pitalium.db.connectionString" をキーとして取得します。

String connectionString = (String) capabilities.getCapability("pitalium.db.connectionString");
Connection connection = DriverManager.getConnection(connectionString);
IDatabaseConnection databaseConnection = new DatabaseConnection(connection);

データベースの操作

最後に、データを挿入します。
DbUnitで標準に規定されたデータの操作方法を紹介します。

 オペレーション  概要
 INSERT  データセットのインサートを行う。
 CLEAN_INSERT  データセットに存在するテーブルのデータが全て削除された後、データセットのデータがインサートされる。
 UPDATE  データセットのデータのうち、既存データが存在するものがアップデートされる。
 REFRESH  データセットのデータのうち、既存データが存在するものはアップデートされ、存在しないものはインサートされる。
 DELETE  データセットで指定されたデータが削除される。
 DELETE_ALL  データセットで指定されたテーブルの全データが削除される。
 TRUNCATE_TABLE  データセットで指定されたテーブルの全データが削除される。
DELETE_ALLより高速だが、DROP-CREATEのため、データのロールバックが出来ない等の副作用がある。

今回はCLEAN_INSERTを使用し、全データを作り直します。

DatabaseOperation.CLEAN_INSERT.execute(databaseConnection, dataSet);

初期化操作全体

@Before
@Override
public void setUp() {
   super.setUp();

   // Capabilitiesに設定した接続先を取得する
   String connectionString = (String) capabilities.getCapability("pitalium.db.connectionString");

   // データベースの初期化を実行する
   try {
        Class.forName("org.h2.Driver");
   } catch (Exception e) {
       throw new RuntimeException(e);
   }
   try (InputStream in = getClass().getResourceAsStream("init_data.xlsx");
         Connection connection = DriverManager.getConnection(connectionString)) {
       // DataSetの生成
       IDataSet dataSet = new XlsDataSet(in);
       // DatabaseConnectionの生成
       IDatabaseConnection databaseConnection = new DatabaseConnection(connection);

       // 高速化用、バッチ処理設定
       databaseConnection.getConnection().setAutoCommit(false);
        databaseConnection.getConfig().setProperty(DatabaseConfig.FEATURE_BATCHED_STATEMENTS, true);
        databaseConnection.getConfig().setProperty(DatabaseConfig.PROPERTY_BATCH_SIZE, 1000);
        databaseConnection.getConfig().setProperty(DatabaseConfig.PROPERTY_FETCH_SIZE, 1000);

       // データを全て削除し、挿入しなおす
       DatabaseOperation.CLEAN_INSERT.execute(databaseConnection, dataSet);
        databaseConnection.getConnection().commit();
   } catch (Exception e) {
       throw new RuntimeException(e);
   }
}

※※※
上記の様にAutoCommitを設定せず、またバッチ処理を有効化することで
大量データの処理が非常に高速になる場合があります。

4.WebアプリのURLを取得

Pitaliumにはテスト対象ページのベースURLを testAppConfig.json に記述すると
WebDriver#getへ渡すURLは、ベースURLからの相対パスで記述することができます。  

しかし今回のテストではブラウザ毎にアクセス先を変更する必要があるため
ベースURLはPitaliumの自動補完を使用せず、Capabilitiesから取得します。

@Test
public void deleteUser() throws Exception {
    String baseUrl = (String) capabilities.getCapability("pitalium.baseUrl");
    driver.get(baseUrl + "user/");

   ...
}

5.操作後のデータベースアサーション

Webアプリを介して何らかの操作をした後、データベースに登録されているデータをDbUnitで確認します。
DbUnitはDataSetをDataSet単位、または内包するTable単位で比較することができます。

@Test
public void deleteUser() throws Exception {
   ...

   // データベースの値をチェックする
   String connectionString = (String) capabilities.getCapability("pitalium.db.connectionString");
   try (InputStream in = getClass().getResourceAsStream("result_data.xlsx");
         Connection connection = DriverManager.getConnection(connectionString)) {
       // 正解データが含まれるエクセルファイルからDataSetを生成
       IDataSet expectedSet = new XlsDataSet(in);
        IDatabaseConnection databaseConnection = new DatabaseConnection(connection);
       // データベースから比較元のDataSetを生成
       IDataSet actualSet = databaseConnection.createDataSet();

       // 全テーブルの値をまとめてチェックする
       Assertion.assertEquals(expectedSet, actualSet);
   }
}

DataSetまたはTable同士を org.dbunit.Assertion#assertEquals メソッドを使用して比較します。
DataSet、Tableに対してJUnitやhamcrestのassertEqualsを使用して比較するとテストは必ず失敗してしまいますので注意してください。

テストに使用するWebアプリケーション

概要

今回のテストサンプルは静的ページではなくデータの削除を含むWebアプリです。
フレームワークとして Spring Boot を、データベースとして H2 Database を使用しています。

このWebアプリは以下の機能を持ちます。

  • データベースに登録されているユーザーを一覧表示する
  • 選択されたユーザーをデータベースから削除する

データベースを起動する

Webアプリを立ち上げる前に、以下の手順の通りデータベースを起動します。

  1. h2 のウェブサイトから Platform Independent のzipアーカイブをダウンロードします。  
    本記事執筆時点での最新バージョンは 1.4.193 (2016-10-31) です。
  2. ダウンロードしたzipアーカイブを解凍します。
  3. 解凍したディレクトリの中にある h2/bin/h2.bat をダブルクリックし、h2データベースを起動します。
  4. Webブラウザが開き、h2コンソールのログイン画面が表示されます。
    h2-console.png
  5. 上記設定でログインを実行するとh2データベースに接続できます。  
    なおWindows環境では、 jdbc:h2:tcp://localhost//test_0 の接続文字列で接続すると  
    C:\Users\{ユーザー名}\test_0.mv.db というデータファイルが生成されます。

Webアプリを起動する

Webアプリを以下の手順で起動します。

  1. Webアプリのソースコードをこちら(Github:TODO)からダウンロードします。
    または以下のコマンドを使用して、ソースコードをクローンします。
    git clone https://github.com/todo
  2. Antを使用してパッケージを生成し、実行します。
    ant -lib ant-lib\spring-boot-antlib.jar build.xml
    java -jar build\pitalium-sample-db-web.jar

Webアプリのデータベース参照先、起動ポートを変更する

今回のWebアプリは同時テストするブラウザの個数に合わせて複数起動しなければなりません。
そこでSpringのプロファイル機能を利用して、データベースの参照先およびWebの待ちうけポートを変更します。
初期状態ではプロファイルは2つ設定してあり、最大2ブラウザの同時実行が可能です。

3ブラウザ以上を同時に実行するにはプロファイルを編集し、新規プロファイルを追加します。
編集は src/main/resources/config/application.yml を修正します。

application.yml
spring:
  profiles:
    active: pita-test-00
  datasource:
    username: sa
    password:
    driver-class-name: org.h2.Driver
  jpa:
    hibernate:
      ddl-auto: update

---
spring:
  profiles: pita-test-00
  datasource:
    url: jdbc:h2:tcp://localhost/~/test_0
server:
  port: 18080

---
spring:
  profiles: pita-test-01
  datasource:
    url: jdbc:h2:tcp://localhost/~/test_1
server:
  port: 18081

クローンした時点ではapplication.ymlは上記の通りのなっています。
各プロファイルはファイル内の "---" によって分けられ、ファイル内の上の部分が全プロファイル共通の設定、
真ん中が1つ目のプロファイル、下が2つ目プロファイルとなっています。

   プロファイル1  プロファイル2
 プロファイル名  pita-test-00  pita-test-01
 デフォルト  ○   
 DB接続先  jdbc:h2:tcp://localhost//test_0  jdbc:h2:tcp://localhost//test_1
 起動ポート  18080  18081

たとえば3つ目のプロファイルを追加するには、application.ymlに以下を追記します。

---
spring:
  profiles: pita-test-02
  datasource:
    url: jdbc:h2:tcp://localhost/~/test_2
server:
  port: 18082

特定のプロファイルで起動するには、起動引数にプロファイル名を追加します。

java -jar -Dspring.profiles.active=pita-test-02 build\pitalium-sample-db-web.jar

ソースコード

参照


Copyright (C) 2012-2017 NS Solutions Corporation, All Rights Reserved.