ハンズオンセクション 2

概要

さて、ハンズオンの続きです。

"データ登録をしてConditionBeanで基本の検索" をしていきましょう。

事前準備

org.docksidestage.handson.exercise.HandsOn02Test クラスを src/test/java (Testクラス置き場) に作成してください。 このクラスは UnitContainerTestCase を継承します。また、ERDを開いておくと良いでしょう。

マスタデータの登録

ここでいうマスタデータとは、会員ステータスなどの固定的なテーブルを指します。(開発環境でも、本番でも変化しないようなテーブル、例えば区分値など)

マスタデータがないことを確認

localdb/login-mysql-root.bat|sh で MySQL にログインして、会員ステータスが一件も存在しないことを確認してください。

e.g. 会員ステータスの件数を取得 @SQL
-- MaihamaDBに接続
use maihamadb;

-- 会員ステータスのカウント検索
select count(*) from MEMBER_STATUS;

マスタデータを配置して再びReplaceSchema

tutorial/material/dbflute/playsql-loaddata-common.zip の playsql/data/common/xls/10-master.xls をDBFluteクライアントの playsql 配下に同じディレクトリ構造で配置し、ReplaceSchemaを実行してください。

e.g. マスタデータ用のエクセルファイルの配置場所 @Directory
PROJECT_ROOT
 |-...
 |-dbflute_maihamadb
 |  |-dfprop
 |  |-...
 |  |-playsql
 |  |  |-data
 |  |  |  |-common
 |  |  |     |-xls
 |  |  |        |-10-master.xls
 |  |  |-replace-schema-00-system.sql
 |  |  |-replace-schema-10-basic.sql
 ...

マスタデータが入ったことを確認

先ほどの会員ステータスのカウント検索の結果が 0 でないことを確認してください。

テストメソッドの作成

こんどは、テストデータの登録ですが、先にテストメソッドを書いて、テストデータが入っていることをアサートしてみましょう。 まだデータを登録する前ですから、テストは落ちるはずです。

テストデータがあることをアサートするテスト

HandsOn02Test に、会員(MEMBER)のデータをアサートするテストを書いて "落ちること" を確認してください。テストメソッド名は test_existsTestData() とします。

このプロジェクトでは、メソッド名が test で始まることで、それがテストメソッドであると認識されます。 今後、テストを作成する際は、必ず "test何々" という形式でメソッドを作成してください。

テストメソッドの雛形

_test と打って ctrl + space して enter するとテストメソッドの雛形が作成されます。

テストコードのお約束コメントの Arrange や Act のコメントが付与されているかと思います。 実はこれは、セクション1でエディターテンプレートを設定したからです。 このように、Eclipseのコード補完を拡張することができます。

e.g. テストメソッドのコード補完 @Java

public class HandsOn02Test extends UnitContainerTestCase {

    _test // _test と入力して ctrl + space して enter
}
--

public class HandsOn02Test extends UnitContainerTestCase {

    public void testname() throws Exception { // name の部分が入力モードに
        // ## Arrange ##

        // ## Act ##

        // ## Assert ##
    }
}

メソッド名とBehaviorの宣言

テストメソッド名は、"test_existsTestData()" とし、MemberBhv を private のインスタンス変数として宣言してください。 Lasta Di では、@Resource というアノテーションを付けるとDI対象となります。(厳密にはテストクラスではアノテーションは不要なのですが習慣として)

インスタンス変数の名前の入力のところ (MemberBhvの後ろ一つ空白を空けたところ) で ctrl + space を押すと、memberBhv という名前を候補として選べます。(間違い防止のためにも積極的に利用しましょう)

e.g. test_existsTestData() の実装準備 @Java
public class HandsOn02Test extends UnitContainerTestCase {

    @Resource
    private MemberBhv memberBhv;

    public void test_existsTestData() throws Exception {
        // ## Arrange ##

        // ## Act ##

        // ## Assert ##
    }
}

テストコードの実装

そして、条件なしのシンプルな検索処理を実装してみましょう。(講師と一緒になぞって実装)

Behavior の selectCount() を使って select count(*) を実行し、assertTrue()メソッドを使ってアサートしてみましょう。 (assertTrue() は、"assT" とまで打って ctrl + space すれば補完できます)

テストコードの実行

ConditionBeanを使って会員ステータスが存在することをアサートするテストを実装して実行し、テストが "落ちること" を確認してください。テストが正しければ、データはまだ入っていないので例外が発生し、JUnitのバー表示が赤くなるはずです。

テストを実行する際は、そのテストメソッドの中にカーソルがある状態で ctrl + 0 を押すと、そのテストが実行されます。これは Quick JUnit のショートカットです。

テストデータの登録

テストデータを配置して再びReplaceSchema

tutorial/material/dbflute/playsql-loaddata-ut.zip の playsql/data/ut/xls/20-member.xls, 30-product.xls をDBFluteクライアントの playsql 配下に同じディレクトリ構造で配置し、ReplaceSchemaを実行してください。

(...ReplaceSchema実行中)

ログを読んでみましょう

落ちるはずです。ログを追って 何が起きたのか? を掴んでみましょう。 コンソールが見づらければ、DBFluteクライアント(dbflute_maihamadb)の log/dbflute.log を見るとよいでしょう。

defaultValueMap.dataprop

20-member.xls を開いてみてみてください。NotNull制約のついている共通カラムのデータがありません。 ここでは、(DB上ではなく)ReplaceSchemaにデフォルト値を設定して解決しましょう。 同じディレクトリに以下の内容で defaultValueMap.dataprop というファイルを作成して、ReplaceSchemaを再実行してみましょう。

e.g. 共通カラムのデフォルトテストデータの設定 @defaultValueMap.dataprop
map:{
    ; REGISTER_DATETIME = sysdate
    ; REGISTER_USER     = foo
    ; UPDATE_DATETIME   = sysdate
    ; UPDATE_USER       = foo
    ; VERSION_NO        = 0
}

テストが通ることを確認

再度テストを実行し、テストが通ってJUnitのバー表示が緑になることを確認してください。 F11 を押すと、さっき実行したテストが再実行されます。これも Quick JUnit のショートカットです。

テストデータの閲覧

さて、ここでじっくり ConditionBean について学んでみましょう。(講師によるCB談議あり)

せっかくなので、どのようなデータが入っているかさらに見てみましょう。 以下のテストを作成してください。(メソッド名の先頭にtestを付けましょう。メソッド名はいい感じに...)

会員名称がSで始まる会員を検索 (これはタイトル、この中にも要件が含まれている)
  • 会員名称の昇順で並べる (これは実装要件、Arrange でこの通りに実装すること)
  • (検索結果の)会員名称がSで始まっていることをアサート (これはアサート要件、Assert でこの通りに実装すること)
会員IDが1の会員を検索
  • 一件検索として検索すること
  • 会員IDが 1 であることをアサート
生年月日がない会員を検索
  • 更新日時の降順で並べる
  • 生年月日がないことをアサート

アサートだけでなく、データを確認する意味でのログの出力も実装すると良いでしょう。 ログに何を出力するかは自由です。(今後のテストも全て同様)

コード補完を駆使して実装

DBFluteは、Java (コンパイル言語) の良さを最大限活かしていくことに重きを置いています。

ぜひ、ショートカットとコード補完を駆使して、気持ちよく実装していきましょう。 最初は全然ゆっくりでOKです。ハンズオンでじっくり手に馴染ませて、本番(業務の実装)でスピーディーに実装できればいいわけなのです。

ConditionBeanの機能を探したいときはどうする?

ぜひ、"ディベロッパーのFAQ" をじっくりお読みください。

ディベロッパーのためのチュートリアル - ディベロッパーのFAQ

まずは、DBFluteに関係なく やりたいことを明確にすること これを重要視しています。 それさえハッキリすれば、その一つ一つの "目的" から、おのずと機能が探しやすくなっているはずです。

(ConditionBeanを覚えるためにやっているというのに...) いきなりConditionBeanのことを考えるのではなく、要件をよく読み、ERDのテーブル構造と照らし合わせて検索イメージを湧かせることが大切です。

すでに何十人の人にハンズオンを行っていますが、(もちろん経験の差もありますが) 自力で機能を見つけられる方と苦戦される方の大きな違いは、そこにあると感じています。 見つけ方、それがわかってしまえば、機能を丸暗記する必要はないのです。

これは DBFlute に限らない話で、覚えることのあまりに多過ぎるこの世界でやっていくための、とても重要なスキルと言えると考えていますので、ぜひここで意識してみてください

Java8 なら OptionalEntity

Java8であれば(1.0.xでもisCompatibleBeforeJava8をfalseにしていれば)、 selectEntity()の戻り値は OptionalEntity となります。Java8で導入された Optional を Entity に適用したものです。

詳しくは、selectEntity() のドキュメントをご覧ください。

模範解答的な

模範解答的な実装を紹介しています。(参考までに)

次のセクション

さて、次のセクションへ