*

JUnit入門その7[Eclipse4.4のJUnitプラグインとDBUnitの併用(更新系のテストの実装)]

公開日: : 最終更新日:2016/12/05 DBUnit, Eclipse, Java, JUnit , ,


スポンサードリンク



JUnit入門その6[Eclipse4.4のJUnitプラグインとDBUnitの併用(便利に利用するためのユーティリティの作成)]
ではDBUnitを便利に利用するためのユーティリティ(と言っても基底クラスでが・・・)の説明をさせていただきました。

今回は、更新系のテストの実装方法の説明をさせていただきたいと思います。

本エントリーの内容は以下の通りです。

  1. 更新系テストの実装方法の説明
  2. 更新系テストの実装例とその説明
  3. 期待値データとデータベースの比較方法


1 更新系テストの実装方法の説明

更新系テストにおけるポイント

更新系のテストと一括りで書いてますが、実際には、新規作成(Insert)、更新(Update)、削除(Delete)が含まれています。

各更新系のテストでは、DBアクセスロジックが正しく実装されている事を担保するだけではなく、DBのメタデータ(主キー、カラムの属性や、カラムの長さ等)がDB設計通りになっているかを確認する必要があります。

上記の内容は、DBUnitを利用しなくてもテストを実装可能ですが、テスト実行後のDBデータの検証はDBUnitを利用しないと難しいといえます。ここがDBUnitの真価を発揮する所です。

新規作成のテストの実装時のポイント

テスト対象となる。DBアクセスロジックの操作対象テーブルの各カラムに対するテストケースのポイントは以下のの通りです。

  • nullが許可されているカラムにnullが登録できること。
  • not null制約のカラムにnullが登録できないこと。
  • カラム長が存在する場合、最大長のデータが登録できること。
  • カラム長が存在する場合、最大長より長いデータが登録できないこと。
  • 一意制約のカラムは、それに違反するデータが登録できないこと。
  • 参照整合性制約が設けられたカラムには、それに違反するデータが登録できないこと。

当然ですが、DBアクセスロジックのホワイトボックステスト的な観点でのテストケースは必須です。

あと、これは私の好みの問題かもしれませんが、新規作成でかつ、新規レコードが作成されないパターンのテストでも、テスト実行後のDBデータの検証処理は実装しておくべきだと考えます。前提値データをそのまま期待値データに指定すればOKですのでテストデータが増える事もないです。

とは言え、例外が発生することを@Testアノテーションのexpectedを利用して検証する場合はその方がスマートだとも言えます。

もう1点、気になるポイントとして、複数テーブルにレコードを作成する時のエラー処理ですね
テーブルA、テーブルB、テーブルCとの順番で1レコードずつ新規作成する処理の場合は、テーブルCにレコードを作成失敗時のロールバック処理が正しく実装されている事のテストケースは必須だと言えます。エラー処理を言い出すときりがないですが・・・

更新のテストの実装時ののポイント

テスト対象となる。DBアクセスロジックの操作対象テーブルの各カラムに対するテストケースのポイントは、新規作成の時と同様です。

DBアクセスロジックのホワイトボックステスト的な観点でのテストで注意するポイントとしては

  • 更新対象のレコードが1件存在する場合
  • 更新対象のレコードが複数件存在する場合
  • 更新対象のレコードが存在しない場合
  • 他のトランザクションの排他処理により更新処理が失敗する場合

他のトランザクションによる排他に関しては、リトライ処理を組み込んでいる場合は、リトライで更新がうまくいくテストパターンも必要となります。

繰り返しになりますが、それ以外のポイントはDB定義の検証のテストケースとなります。

削除のテストの実装のポイント

更新のテストのポイントと同様となります。

2 更新系テストの実装例とその説明

ユニットテストに利用するデータベースは「HyperSQL」となります。
環境作成に関しましては、
「HyperSQL」の環境を作成し、Eclipseの「DBViewer」プラグインを利用してSQLを発行してみる
を参照ください。

テストに利用するテーブルの説明

以下のようなテーブル:USERTBLを利用します。

「HyperSQL」の管理ツールやEclipseの「DBViewer」プラグインでデータベースに接続し、SQLを発行してください。

テスト対象のDAO

テスト対象のDAOは以下の通りです。
JDBCConnectionUtilにつきましては、
JUnit入門その6[Eclipse4.4のJUnitプラグインとDBUnitの併用(便利に利用するためのユーティリティの作成)]
をご覧下さい。

何の変哲もない、面白味に欠けるコードですが、このUserDAOに対してテストを実装して行きます。

UserDto.javaは以下のようになります。

更新系のテストクラスの生成

UserDAOをクリックした状態で、「新規Javaクラス作成」ボタンの右側をクリックします。
スクリーンショット 2015-04-13 15.44.24

すると、以下の画像のリストが表示されますので、「JUnitテスト・ケース」をクリックします。
スクリーンショット 2015-04-13 15.51.52

すると以下のような画面が表示されます。
スクリーンショット 2015-04-13 15.54.02

クラス名にUserDAOTest、テスト元クラスにUserDAOが既にセットされています。
スーパークラスをdbunitutil.DatabaseTestCaseExに変更し「次へ」ボタンをクリックします。
スクリーンショット 2015-04-13 15.58.02

dbunitutil.DatabaseTestCaseExにつきましては、
JUnit入門その6[Eclipse4.4のJUnitプラグインとDBUnitの併用(便利に利用するためのユーティリティの作成)]
をご覧ください。

次に表示される画面では、以下の画像の赤枠部分のチェックボックスをチェックし、「完了」ボタンをクリックしてください。
スクリーンショット 2015-04-13 16.01.14

このチェックによって、テスト元クラスのチェックを入れたメソッドに対するテストのひな形が自動生成されます。
と言っても名前とアノテーションだけなんですが・・・

生成されたクラスは以下のようになりました。

更新系のテストの実装前の前準備

@TestDataをテストクラスに付与

DatabaseTestCaseExでは、クラス定義に@TestData(baseData=”./testdata/testdata.xls”)のようなアノテーションを付与することで、前提値データ(パス=./testdata/testdata.xls)がデータベースにセットアップされる機能を実装していたのでした。

./testdata/testdata.xlsは、Eclipseのパッケージ・エクスプローラーで見ると以下のような位置に存在します。
スクリーンショット 2015-04-13 18.12.51

詳細は、JUnit入門その6[Eclipse4.4のJUnitプラグインとDBUnitの併用(便利に利用するためのユーティリティの作成)]をご覧ください。

それにしてもNullPointerExceptionが発生するのは良くないですね・・・

と言う事で、@TestData(baseData=”./testdata/testdata.xls”)をUserDAOTestに付与しました。

./testdata/testdata.xlsの内容は以下のようになります。
スクリーンショット 2015-04-13 18.16.36

db.propertiesの内容を変更

前回までは「Java DB」を利用していましたので、「HyperSQL」につながるよう設定を変更する必要があります。
変更後のdb.propertiesは以下のようになりました。

HyperSQLのJDBCドライバーのjarをビルドパスに追加

HyperSQLのlib配下に存在するhsqldb.jarをビルドパスに追加する必要があります。

詳細は
Eclipse4.4(Java)におけるビルド・パス関係の設定方法[JRAおよびクラス・フォルダー/ライブラリー]
をご覧ください。

Apache POIのバージョンを3.2-FINALに変更

現在のDBUnit(2015年4月現在は2.4.9)と最新のApache POIは相性が悪いようです。

http://archive.apache.org/dist/poi/release/bin/poi-bin-3.2-FINAL-20081019.tar.gz
から3.2-FINALを取得し、POIのjarを差し替える必要があります。

なお、xlsファイルに文字列しか存在しない場合は最新のPOIでも問題なく動作します。

現在のDBUnit(2015年4月現在は2.4.9)を最新のApache POIで動作させると以下のような例外が発生します。

新規作成のテストの実装例

新規作成のテストを実装してみます。実際のメソッドはtestCreateUserとなります。

新規作成のテストの実装例

データベース定義のテスト

「1 更新系テストの実装方法の説明」の「新規作成のテストの実装時のポイント」に関するテストを実装します。
とは言っても全てのパターンを網羅すると長くなりますので、数パターンのだけ実装してみます。

・null、not nullの検証テスト
addrはnot null制約が付与されいますので、addrにnullをセットした時に例外が発生するとのテストを実装します。

実際には、testCreateUserをコピーして、testCreateUser_addrにnullがセットできない検証メソッドを作成し、@TestアノテーションのexpectedにSQLException.classを指定するとの方法としました。

テストを実行してみると、失敗します。
スクリーンショット 2015-04-14 13.50.51

java.sql.SQLIntegrityConstraintViolationExceptionがスローされているのだから、expected=SQLException.classと記載しているので、成功のはずですが・・・

色々試行錯誤した結果、UserDAOTestがDatabaseTestCaseExを継承していることが問題の原因でした。
DatabaseTestCaseExはDatabaseTestCaseを経由してjunit.framework.TestCaseの継承クラスです。

JUnit4系では、テストクラスでもjunit.framework.TestCaseを継承しなくてOKとなっており、この継承関係を作ってしまうと@Test(expected=が正常に動作しないようです。

DatabaseTestCaseExの作りを考え直さないといけないですね・・・

とりあえず今回はtry catchで対応するように変更してみます。

これでテストは成功しました。
スクリーンショット 2015-04-14 14.05.41

実際には、主キーはnot null制約を含むので、nameカラムに対するテストも実装すべきですが、今回は省略させていただきます。

・最大長を超えるデータが登録できないテスト
次に、nameに21文字、addrに41文字セットした時のテストを実装します。

うんうん、ちゃんとテストが成功しました。

このテストメソッドでは、nameとaddrを同時に検証していますので、どちらのカラムに対する例外でもテストは成功しますが、nameは21文字登録できて、addrだけ41文字登録できない場合でもテストは成功してしまいますので、本来は別々に検証すべきです。

DAO自体のテスト

createUserメソッドのテストとしては、引数にnullが渡された時と、普通に登録が成功する時(戻り値がtrue)、登録が失敗する時の3パターン(戻り値がfalse)が存在すると思います。

と思いましたが、例外がスローされるので登録が失敗するパターンは現実的に存在しませんね・・・

それ以外は「データベース定義のテスト」の範疇です。

厳密には、データベースの排他処理も考慮すべきですが、今回は省略させていただきます。
・引数にnullが渡された時のテスト
現在のcreateUserメソッドの引数にnullを渡して呼び出すとNullPointerExceptionが発生します。
とっても格好が悪いですね、せめて引数チェックを行って、nullの場合はIllegalArgumentExceptionをスローするよう変更しました。

テストメソッドは以下の通りです。

テストも問題なく成功しました。

・普通に登録が成功する時のテスト
このテストメソッドは以下のようになりました。

nameに20文字、addrに40文字、ageにInteger.MAX_VALUEを指定してUserDaoのcreateUserを呼び出しています。

呼び出しが成功した事を確認した後、期待値データ(./testdata/expecteddata1.xls)とデータベースの中身を比較しています。

./testdata/expecteddata1.xlsの中身は以下のようになります。データが長いのでほとんど見えてませんが・・・
スクリーンショット 2015-04-14 19.14.57

期待値データとデータベースの比較方法につきましては後述させていただきます。

更新・削除のテストの実装例

更新・削除のテストの実装例の説明もと思ったのですが、新規作成のテストと考え方は同じですので省略させていただきます。

3 期待値データとデータベースの比較方法

期待値データとデータベースの比較方法の説明をさせていただきます。

前述の「新規作成のテストの実装例」で記載させていただいた比較は、期待値データに存在する全てのテーブルのデータと、データベースに存在するそのテーブルのデータを比較する実装例となります。

DBUnitにはこの比較以外に、テーブルを指定した比較、クエリーを指定した比較が存在します。

期待値データに存在する全てのテーブルの比較

「普通に登録が成功する時のテスト」がコード例となります。
実際にはorg.dbunit.AssertionクラスのassertEqualsメソッドを利用します。

比較するテーブルの認識法則

期待値データにA_TABLE、B_TABLE、C_TABLEが存在した場合は、データベースのA_TABLE、B_TABLE、C_TABLEにそれぞれ登録されているデータと期待値データのA_TABLE、B_TABLE、C_TABLEに登録されているデータを比較し、一致すればAssertion.assertEqualsが成功します。

カラムは全てのカラムが比較対象となります。もしデータベースのA_TABLEに存在するカラムが、期待値データのA_TABLEで全て定義されていない場合は以下のような例外が発生します。

比較時のソート順

期待値のデータは、行データの定義順(xls内の順番通り)で、データーベースのデータのソート順は、ソート未指定時の順番となりますので、データが全く同じ場合でも、xlsの行の並びがソート未指定時の順番と異なる場合はAssertion.assertEqualsは失敗します。

前述の「新規作成のテストの実装例」のexpecteddata1.xlsの中身が以下の内容であった場合はテストは失敗します。
スクリーンショット 2015-04-14 19.48.25

スクリーンショット 2015-04-14 19.51.14

障害トレースの1行目は以下のようになります。

テーブルを指定した比較

org.dbunit.database.QueryDataSetを利用することで、比較したいテーブルを指定することが可能になります。

と言っても、期待値のxlsにaddTableしたテーブル以外のシートが存在する場合は、その時点でAssertion.assertEqualsは失敗しますので、現実的にはこの方法だけでは用途はございません。

期待値のxlsに含まれるaddTableしたシートだけを含んだIDataSetを作り出さないと使えないとの意味です。
この点については別エントリーで記載させていただこうと考えております。

クエリーを指定した比較

Assertion.assertEqualsByQueryを利用することで、より細かい設定での比較が可能となります。

API仕様としては以下の通りです。

実際のサンプルコードは以下の通りです。

JUnit入門その7[Eclipse4.4のJUnitプラグインとDBUnitの併用(更新系のテストの実装)]は以上です。


スポンサードリンク



関連記事

利用すると生産性が格段に向上する厳選Eclipseショートカット集

今回のエントリーは、利用すると生産性が格段に向上するEclipseのショートカット集となります。

記事を読む

Javaによる非同期処理入門その1[非同期処理の実装方法の概説]

Javaによる非同期処理に関するエントリーを前々から作成したいと思っていたのですが、ついに作成してみ

記事を読む

Eclipse(4.3,4.4)の使い方[パースペクティブのツールバーのカスタマイズ(「コマンド・グループ可用性」と「ショートカット」タブ)]

「パースペクティブのカスタマイズ」画面には、以下の4つのタブが存在しております。 ツール・バ

記事を読む

Eclipseの「DBViewer」プラグインの使い方[前編]

「HyperSQL」の環境を作成し、Eclipseの「DBViewer」プラグインを利用してSQLを

記事を読む

Selenium入門その6[Selenium3でWebDriver(Java/Junit4)の環境を作成しEdge,Chrome,Firefoxで確認してみる]

Selenium3も3.0.1がリリースされましたし、今後は本格的にSelenium3が利用されてい

記事を読む

Eclipseの「JSDT-jQuery」プラグインでJQuery(JavaScript)のコード補完が可能な環境を作成する

Eclipse for JavaEE Developer等のWeb開発系のEclipseがインストー

記事を読む

Java超入門 with Eclipse[4:クラスに関する基礎知識(修飾子とクラスとインスタンスと変数)]

前回は、Javaの基本であるクラスの基本的な知識をざっくりと説明させていただいたあと、 packa

記事を読む

JDK8(Java8)のインストール方法[Windows]

本エントリーは、Windows7 64bitにJDK8(Java8)をインストールする説明を記載させ

記事を読む

Selenium入門その5[ページオブジェクトパターン(Page Object Design Pattern)を利用して変更に強いテストを作成する方法]

Selenium入門その2 では「UIマップファイル」と言う仕組みが存在していることに言及させてい

記事を読む

Eclipse(4.4)でJava言語のリファクタリング機能の使い方[「メソッド・シグニチャーの変更」と基本的な抽出処理、及び「インライン化」、「定数の抽出」]

本エントリーでは、Eclipse(4.3)でJava言語のリファクタリング機能の使い方に引き続き

記事を読む

Message

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

Selenium入門その6[Selenium3でWebDriver(Java/Junit4)の環境を作成しEdge,Chrome,Firefoxで確認してみる]

Selenium3も3.0.1がリリースされましたし、今後は本格的にS

Selenium利用時のトラブルシューティング方法[クリック編]

Seleniumは便利なテスト自動化ツールですし、今後は更なる利用者の

Java8のラムダ式とStream APIを利用してコーディング量の削減サンプル集

Java8になりラムダ式と「Stream API」が利用できるようにな

Selenium入門その5[ページオブジェクトパターン(Page Object Design Pattern)を利用して変更に強いテストを作成する方法]

Selenium入門その2 では「UIマップファイル」と言う仕組みが

Javaによる非同期処理入門その1[非同期処理の実装方法の概説]

Javaによる非同期処理に関するエントリーを前々から作成したいと思って

→もっと見る

Optimization WordPress Plugins & Solutions by W3 EDGE
PAGE TOP ↑