2012年2月13日月曜日

AndroidのUnit Testをするなら読んでおきたいコード

単なるリンクメモ


Activityのテスト関連

  • android.test.ActivityInstrumentationTestCase2<T>
    • Activityのテストを書く時に継承するクラス。有無を言わず読んどけ。
  • android.test.ActivityTestCase
    • ActivityInstrumentationTestCase2<T>が継承しているクラス。とりあえず、すこしだけ読んどいたほうがいいかも。
  • InstrumentationTestCase
    • ActivityInstrumentationTestCase2<T>が最も依存しているクラス。より高度な知識を得たい時には読んどいたほうがよい。
  • android.test.InstrumentationTestRunner
    • テストを起動するActivityと同等のもの。もしJUnitと同等のレポートを出力する場合には、このクラスを改造するので読んでおいたほうがよい。
  • android.app.Instrumentation
    • InstrumentationTestRunnerの基底クラス。JUnitと同等のレポート出力するために読んでおきたい。



2012年2月12日日曜日

単語がわからんでもどうにかなる英字新聞

ど~も。


受験生の頃から英単語を覚えるのが苦手で、今でも単語がよくわからなくて困っていたりします。


まあ、そういう時に文脈から推測する方法を身につけておけば、安心です。意外と何とかなります。


というわけで、今日(2012/02/12)のTHE NIKKEI WEEKLYから例文を取り出してみました。


Japan tested, Asia approved

Marketing strategies honed in Ginza give Western designers confidence in rest of Asia.

It is no secret: Much of the rest of Asia is overshadowing Japan's economy. In at least one regard, however, the Land of the Rising Yen remains the king of consumerdom: Not only is Japan a major source of earnings for the West's luxury labels, it is a laboratory for new marketing strategies.



まず、見出し1から。

「Japan tested, Asia approved」から、「日本テスト、アジア認められる」こんな感じですね。
受験英語ではどうやら後から訳すことが多くて、後ろから理解したい気がしなくもないですが、左から右へ因果関係がたいてい書かれていますので、この流れを掴んでおきましょう。



見出し2。

わからない単語があります。
「hone」「confidence」。
なんだかわかりませんね。
とりあえず、ほうっておいて読んでいきます。
訳していくと、「マーケティングの戦略…銀座で」「西欧のデザイナーに…を与える」「のこりのアジアでの」となります。

見出し1から推測すると、「日本で確認して、アジアでうまくいく」みたいな因果関係が有りそうなので、この部分も同様に解釈してみます。
で、「日本で確認」することによってデザイナーが何を与えられるかと考えると、うまく行ったという「自信」が与えられるのでは?と推測できます。
というわけで、「confidence」は「自信」ではないかと推測できます。

で、ここまでいくと、「honed」という単語は意味がわからなくてもなんとかなりそうです。おそらく「tested」とほぼ同意なのかと推測できます。

というわけで、訳すと「マーケティング戦略を銀座で試すことによって、西欧のデザイナーは自信を持って他のアジアの国々に展開することができる」となります。



本文1

「It is no secret」はいいですよね。「秘密でないこと」=「明らかなこと」って感じですね。

さて、「overshadowing」という単語がよくわかりませんね。
「shadowing」とすると、なんか影を追っかけているのか、もしくは「影になっている」という感じがしますが、「over」が付いているので、なんかよくわかりませんね。

まあ、でも前に「明らかなこと」と説明が付いているので、現在の経済状況を鑑みると、日本よりも他のアジアのほうが元気なので、そういうような意味でとっても構わなそうですね。

というわけで、「Much of the rest of Asia is overshadowing Japan's economy.」を訳してみると「他のアジアの国々のほうが日本の経済よりもいい感じである」となりそうです。



本文2

長いので、「consumerdom」で区切ります。

区切ったのはいいけど、「regard」と「consumerdom」がよくわかりませんね。というか、「consumerdom」にいたっては、造語っぽいですね。

「regard」はよくメールの最後に使いますね。「Best Regards」みたいな感じで。あれも意味わからんで書いているのですが、まあ「物事」というくらいに捉えておけばいい単語なのかなと思っています。

ところで、この文章では「however」という反対の意味を強調する接続詞がついていますね。なので、文としては前の文の反対の意味のことを言おうとしていることがわかります。前の文では「日本やばい、アジアすごい」ということを述べていますので、この文では「日本すごい」ということを述べようとしているというのがわかります。

「Rising Yen」というのは、昨今の日本円に関する情報を考えると、「日本円の高騰、円高」という意味でしょう。
円高になると何がどうなるか考えると、1 euroが130円だったのが80円くらいになっているわけで、今まで1,000 euro=130,000円したバッグが、今では80,000円で買えることになります。

そしてこれまでの文意「日本でテスト、アジアで攻める」という文意からすると、日本での消費はあくまでテストであって、アジアが本命ということになります。
逆に日本人側からの心理で行けば、今までよりも安く買えるので西欧のブランド品を気軽に試せるという話になります。

そうすると「consumerdom」というのは「consumer」消費者を象徴するような意味の単語であるというのが推測が付きます。

ところで「dom」で終わる単語なんか他になかったっけ?と考えてみると、「kingdom」という単語が浮かんできます。「kingdom」は「王座」というイメージがあるので、「consumerdom」は「消費者の座」という意味であると推測できそうです。

まあ、このあたりをまとめると「しかし一つの点においては、昨今の円高によって消費大国の座にいることに変わりはない」と訳せそうです。



本文2後半

「not only」と聞いたらすぐに「but also」を思いつきます。しかし、この文章には「but also」はありません。
ここで、「not only」の対称は「Japan」であることが書かれています。
そしてこれまでの文から対比されるのは「rest of Asia」ですので、暗黙的に「but also rest of Asia」が書いてあると解釈します。

あと、「Not only is Japan」となっていますが、これは倒置法ですね。まあ、何かを強調したい時に使うやつですね。
「but also」が省略されていることから、これは残りの「a major source of earnings」という部分を強調するわけではなくて、それ以外のことを強調しようとしています。
それが何かというと、「,」以降の部分になります。

訳すと「日本だけが主要な収入源として西欧のレーベルに寄与しているわけではない(他のアジアの国も寄与している)」となります。

まあ、のこりの部分はそれほど難しくありませんね。
「(日本は)新しいマーケティング戦略の実験場としても寄与している」となります。
そして、先の倒置法のぶぶんからあわせても、この部分が強調されていて、「日本で新たな製品のテストをしてアジアで稼ぐ」という文意が読み取れてきます。


というわけで、単語がわからなくてもなんとか読んでいくことができます。
英語と聞くとビビってGoogle翻訳さんに頼りたくなりますが、まあ私も頼っていますが、文章の主張自体は推測で大体つかめるので、たまにはgoogle先生に頼らず英文を読んでみてはいかがでしょうか。

2012年2月4日土曜日

JavaFX初心者がJavaFXに挑戦してみた…を修正してみた

昨日のエントリー「JavaFX初心者がJavaFXに挑戦してみた」pom.xmlがひどかったので、修正した。

昨日のアレで問題の箇所は、dllを無駄にコピーした所です。

pom.xml

    <dependencies>
        <dependency>
            <groupId>javafx</groupId>
            <artifactId>javafx</artifactId>
            <version>2.0</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.10</version>
            <scope>test</scope>
        </dependency>
    </dependencies>



このように書いておけば、dll依存地獄に陥らないで済みます。

pom.xml

    <dependencies>
        <dependency>
            <groupId>javafx</groupId>
            <artifactId>javafx</artifactId>
            <version>2.0</version>
            <scope>system</scope>
            <systemPath>C:/Program Files/Oracle/JavaFX 2.0 SDK/rt/lib/jfxrt.jar</systemPath>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.10</version>
            <scope>test</scope>
        </dependency>
    </dependencies>




2012年2月3日金曜日

JavaFX初心者がJavaFXに挑戦してみた

JavaFXに興味はなかったんですが…

javascriptのテストをJUnitから実行できるんでね?


こんなことをつい言ってみてしまったので、まあJavaFX触ってみることにしました。

準備


  • Java 1.7.0_02
  • IntelliJ IDEA … version10です。すみません。
  • Maven3.0.4
  • JavaFX2.0


とりあえず、Java7使っています。Java1.6系でも動くらしいです。

家でのコーディングにはほとんどeclipseを使いません。IntelliJです。

試しにmvnコマンド叩いたら、バージョンが2.2.1というひどい状態だったので、最新の3.0.4を入れました。

JavaFX2.0インストールした記憶がないのに、インストーラーを起動するとすでにインストールされている旨エラーメッセージが表示されて、なんでだろうとC:\Program Files\Javaの中を漁っていましたが、結局、見つからず(´・ω・`)して、32bit版をダウンロードしてインストールし…

っていう時に、インストール先がC:\Program Files\Oracleということを知り、探したらありました。


artifactId…


さて、ビルド周りをきっちりやりたいので、mavenでプロジェクトを作ります。

単純にIntelliJでCreate new Project from Scratchして、maven moduleを選択しただけですが…

さて、javafxもmavenからライブラリーを落としてこよっと思ってmavenrepositoryを検索したら残念なコトにartifactIdがございませんでした。

さて、こういう場合はローカルにあるjarをローカルリポジトリーに登録するらしいです。
特にOracleのプロダクトに関してそういうことが多いようです。


というわけで我々もやってみました。


C:\>workspace\JavaFxWebView > mvn install:install-file -Dfile=jfxrt.jar -DgroupId=javafx -DartifactId=javafx -Dversion=2.0 -Dpackaging=jar


それをpom.xmlに指定して、ってな感じでやると見事!プロジェクトに取り込まれました。


pom.xml




2012/02/04 2:50 修正


DLL地獄!?


ここを参考に超シンプルな実装をしてみました。





Creative Commons License
MikeBrowser by Shinya Mochida a.k.a. mike_neck is licensed under a Creative Commons Attribution 3.0 Unported License.

(∩´∀`)∩ワーイということで、早速コンパイル。


C:\>workspace\JavaFxWebView > mvn clean compile




コンパイル通りました。

では早速実行しましょう。


C:\>workspace\JavaFxWebView > mvn exec:java -Dexec.mainClass="org.mikeneck.jfx.MikeBrowser"




Σ(゚д゚lll)ガーン落ちたー。



C:\Users\mike\.m2\repository\javafx\javafx\bin\mat.dll



mat.dllがないらしい。

まあでもブラウザーを持っていたりするんだから、そうなるよね。

さて、このmat.dllくんはどこにいるのかな?

いた!


C:\Program Files\Oracle\JavaFX 2.0 SDK\rt\binにいるそうです。

残念、これは手でローカルリポジトリーに上げるしかなさそうです。

ということで、手で突っ込んでみた。


では、気をとりなおして、再実行!

やりました!出てくれました!






2012年1月22日日曜日

My aunt's too sudden death

Yesterday my father told me that two or three days ago my aunt had died suddenly in cancer. She had finished fourty to fifty years life that is shorter than Japanese average.

Few years she had been bothered by such a severe hyperesthesia that she couldn't have spend an ordinary life which every middle age ladies can enjoy.

When she and my father were child, she lived in more healthy than my father.

Because she had been seeing my father's weakness, she decided to get a jobs in nurse.

She had wide knowlege about health. She would have been a skillful nurse, if she had not has a severe hyperesthesia.

More excelent her career became, she lost her healthiness.

Finally her health had got lost severely. She had decided to live alone without jobs.

Today her funeral is going to be held.

I cannot take part in it, but I pray for her soul.

2012年1月17日火曜日

TDDと勉強法

昨晩の帰り際にふと思い立ったので、覚書程度に。

オレが高校3年生の時、11月、突如思い立って、物理の勉強に没頭した。

単純なma = Fとかいう公式に載っていることではなくて、もっと運動方程式とは何なのかと根源的に追い詰めた。

その時に役に立った本が『坂間の物理』という本で、えっと、某台予備校に通っていたかつて学生だった人の何人かは知っている物理教師の本だった。

まあ、その教師の物理の授業を受けたことがある人は知っていると思うけど、あんなのは受験生が期待する授業ではない。

ただ、あの人のやっていることはTDDという観点で見ると、非常に理にかなっている。

彼の教育プロセスをもう一度思い出してみた。

  • 真似をさせる→答えは教えてやる。間違えてもいいから、こうなるように計算してみろというのである。
  • 徹底的に真似をさせる→教えてやった答えを、問題文を見ないようにして解けというのである。
  • 高速化させる→もっとエレガントに解答を書けというのである。

なんか、TDDっぽい教育だと思った。

一般的なTDDスタイルの開発

  • 答えはわかっている。テストは落ちる。
  • 答えが合うように、実装を作る。
  • もっとエレガントになるように実装を洗練させる。

なんか似ている。

オレは思い立った1ヶ月間『坂間の物理』に掲載されている108問の問題をすべて、この三段階の方法で演習した。

結果、予備校生になっても物理は超得点源になって、某大学模試で物理の偏差値78とかありえない値を取得した。


ペアプロの学習効果はよく言われているが、実際にはTDDもプログラマーの成長に欠かせない要素があるのではないかと思う。


テストを書くということは、実装を書くのに加えて、テストコードも書かなければならないから、一見無駄に思える。

だが、それは上記に上げたプロセスのまだ第一段階なのではなかろうか?


本当にTDDが力を発揮してくるのは第二段階、第三段階を超えた時で、エレガントな実装を出来るようになった時には、オレが物理を超得意となった状態と同じく、プログラマーはプログラムの実装を超得意と思って自信をもって取り組むことが出来るようになるのではないかと思う。

まあ、脳足りんの考えたことなので、実証もされてないことだし、単なる妄想かもしれない。

ちなみに坂間先生というのは、自分の授業について、後で答えを書いてきてごらん、添削してあげるからと言っていたので、毎週授業でやった範囲の部分の真似を持っていていたら、ちゃんとレビューしてくれた。この部分はこう書くともっとエレガントになるとか、ここは読みづらいからもっと大きく書けとか。

テストも同様で、それをレビューしてエレガントなコードはどういうものなのかを考えていけば、プログラマーは大いに成長するのではないだろうか。




ちなみに、坂間先生はオレが通っていた○進スーパーコースでは人気なかったです。

おわり。

2012年1月14日土曜日

Grails2.0のDomainをTDDしてみる。

出展はいつもどおりの『Grails徹底入門』
の96ページにあるモデル図から。

ここから、今回の対象部分のモデルを抜き出したのが以下の図。
で、今回はこのうち、Shipmentの部分をTDDしていきます。


ドメインの作成


ドメインの作成はいたって簡単です。


$ grails create-domain-class Shipment


これだけで、Shipmentドメインクラスと、ShipmentTestsテストクラスが生成されます。

Shipment.groovy

package grailsshop

class Shipment {

    static constraints = {
    }
}


Shipment.groovy

package grailsshop
import grails.test.mixin.*
import org.junit.*

@TestFor(Shipment)
class ShipmentTests {

    void testSomething() {
        fail()
    }
}


なお、テストクラスはデフォルトではfailになるようになっています。

最初のテスト


Shipment(出荷)はイベントなので、必ず日付をもちます。したがって、nullは禁止です。

それをテストに書きます。

なお、Grails2.0はJUnit4対応しているので、アノテーションを用いることでテストメソッドであることを示せます。

ここではテストメソッド名も変更しています。

また、validateのテストになりますので、前回の結論に書いておいたようにmockForConstraintsTestsメソッドを最初に用いておきます。

Shipment.groovy

package grailsshop
import grails.test.mixin.*
import org.junit.*

@TestFor(Shipment)
class ShipmentTests {

    @Test
    void validateDate() {
        mockForConstraintsTest(Shipment)
        def object = 'date'

        def shipment = new Shipment()
        assert shipment.validate() == false
        assert shipment.errors[object] == 'nullable'
    }
}


実行結果は次のようになります。


grails> test-app grailsshop.Shipment
| Running 1 unit test... 1 of 1
| Failure:  validateDate(grailsshop.ShipmentTests)
|  Assertion failed:

assert shipment.validate() == false
       |        |          |
       |        true       false
       grailsshop.Shipment : null

 at grailsshop.ShipmentTests.validateDate(ShipmentTests.groovy:20)
| Completed 1 unit test, 1 failed in 1930ms
| Packaging Grails application.....
| Tests FAILED  - view reports in target/test-reports
grails>


まあ、Shipmentにはdateというフィールドをまだ実装していないので、落ちるのもやむなしです。

暗黙のnullable : false


そこで、実装に行きます。

とりあえず、ShipmentクラスにDate型のdateを持たせてみます。

Shipment.groovy

class Shipment {

    /**
     * 出荷日付.
     */
    Date date

    static constraints = {
    }
}


この状態でテストを実行してみます。


grails> test-app grailsshop.Shipment
| Completed 1 unit test, 0 failed in 152ms
| Tests PASSED - view reports in target/test-reports
grails>


というわけで、とくにnullチェックの実装を入れていませんが、テストが通りました。

Grailsのドメインクラスにあるフィールドはデフォルトでnullablefalseのようです。

適当に制約をいれていく


Shipment(出荷)、捉え方によるけど、未来の日付は入れられないことにしておきましょう。

(出荷予定であれば話は別ですが…)

それをテストに書きます。

ShipmentTests.groovy

@TestFor(Shipment)
class ShipmentTests {

    @Test
    void validateDate() {
        mockForConstraintsTest(Shipment)
        def object = 'date'

        def shipment = new Shipment()
        assert shipment.validate() == false
        assert shipment.errors[object] == 'nullable'

        shipment = new Shipment(date: dayFromToday(1))
        assert shipment.validate() == false
        assert shipment.errors[object] == 'max'
    }
}


dayFromToday(int)は今日からの日付を取るユーティリティーメソッドです。0を指定すると今日の日付、1を指定すると明日の日付が取得できます。

翌日の日付であった場合は、エラーとなるというテストを記述しています。

で、テストの結果は次のとおりになります。


grails> test-app grailsshop.Shipment
| Running 2 unit tests... 1 of 2
| Failure:  validateDate(grailsshop.ShipmentTests)
|  Assertion failed:

assert shipment.validate() == false
       |        |          |
       |        true       false
       grailsshop.Shipment : null

 at grailsshop.ShipmentTests.validateDate(ShipmentTests.groovy:24)
| Completed 2 unit tests, 1 failed in 96ms
| Packaging Grails application.....
| Tests FAILED  - view reports in target/test-reports
grails>


まず、validate()Assertが落ちます。

落ちた原因を探りたいので、一度テストを修正します。

ShipmentTests.groovy

@TestFor(Shipment)
class ShipmentTests {

    @Test
    void validateDate() {
        mockForConstraintsTest(Shipment)
        def object = 'date'

        def shipment = new Shipment()
        assert shipment.validate() == false
        assert shipment.errors[object] == 'nullable'

        shipment = new Shipment(date: dayFromToday(1))
        shipment.validate()
        assert shipment.errors[object] == 'max'
    }
}


テスト結果


grails> test-app grailsshop.Shipment
| Running 2 unit tests... 1 of 2
| Failure:  validateDate(grailsshop.ShipmentTests)
|  Assertion failed:

assert shipment.errors[object] == 'max'
       |        |     ||       |
       |        |     |date    false
       |        |     null
       |        org.codehaus.groovy.grails.plugins.testing.GrailsMockErrors: 0 errors
       grailsshop.Shipment : null

    at grailsshop.ShipmentTests.validateDate(ShipmentTests.groovy:25)
| Completed 2 unit tests, 1 failed in 81ms
| Packaging Grails application.....
| Tests FAILED  - view reports in target/test-reports
grails>


内容からわかるようにエラーがないということです。

ここで、正しくvalidate()でエラーとなるようにドメインクラスを修正します。

Shipment.groovy

class Shipment {

    /**
     * 出荷日付.
     */
    Date date

    static constraints = {
        date(max: new Date())
    }
}



制約を加えたらテストを実行します。


grails> test-app grailsshop.Shipment
| Completed 2 unit tests, 0 failed in 124ms
| Tests PASSED - view reports in target/test-reports
grails>


ちゃんとパスします。

念のため、今日も大丈夫か確認します。

ShipmentTests.groovy

@TestFor(Shipment)
class ShipmentTests {

    @Test
    void validateDate() {
        mockForConstraintsTest(Shipment)
        def object = 'date'

        def shipment = new Shipment()
        assert shipment.validate() == false
        assert shipment.errors[object] == 'nullable'

        shipment = new Shipment(date: dayFromToday(1))
        assert shipment.validate()
        assert shipment.errors[object] == 'max'

        shipment = new Shipment(date: dayFromToday(0))
        shipment.validate()
        assert shipment.errors[object] == null
    }
}


ポイントとしては、validate()が通るケースでは、assert shipment.validate() == trueのテストを行わない方が良いです。

理由は、これから他にもvalidateするものが増えるので、後々にテストが通らなくなるからです。

テストの実行結果は次のようになります。


grails> test-app grailsshop.Shipment
| Completed 2 unit tests, 0 failed in 81ms
| Tests PASSED - view reports in target/test-reports
grails>


リレーションに関するフィールドの追加とテスト


次にリレーションに関するフィールドの追加とテストです。

先に掲載したモデルから、ShipmentWarehouseOrderの関係は、次のようになります。

  • Shipment - Warehouse
    • ShipmentからみてWarehouseは唯一つ存在し、かつその参照先を保持する必要がある。
    • WarehouseからみてShipmentは0または1つ存在し、その参照先は保持しなくて良い。
  • Shipment - Order
    • ShipmentからみてOrderは唯一つ存在し、かつその参照先を保持する必要がある。
    • OrderからみてShipmentは0または1つ存在し、その参照先は保持しなくて良い。

こういうのを一般的には一対一の片方向の関連とかなんとかいうらしいです。

Grailsのドメインにおいて、これを実現するのがbelongsToです。

では、おもむろにテストを書きます。

ここでは、暗黙のnullable : falseを利用します。

まずはOrderから…

ShipmentTests.groovy

@TestFor(Shipment)
class ShipmentTests {

    @Test
    void validateOrder() {
        mockForConstraintsTests(Shipment)
        def object = 'order'

        def shipment = new Shipment()
        assert shipment.validate() == false
        assert shipment.errors[object] == 'nullable'
    }
}


テストを実行します。


grails> test-app grailsshop.Shipment
| Running 3 unit tests... 1 of 3
| Failure:  validateDate(grailsshop.ShipmentTests)
|  java.lang.NoSuchMethodError: grailsshop.Shipment.getBelongsTo()Ljava/lang/Object;
 at org.grails.datastore.mapping.reflect.ClassPropertyFetcher$GetterPropertyFetcher.get(ClassPropertyFetcher.java:326)
 at org.grails.datastore.mapping.reflect.ClassPropertyFetcher.getPropertyValueWithFetcher(ClassPropertyFetcher.java:218)
 at org.grails.datastore.mapping.reflect.ClassPropertyFetcher.getStaticPropertyValue(ClassPropertyFetcher.java:233)
 at org.grails.datastore.mapping.model.config.GormMappingConfigurationStrategy.establishRelationshipOwners(GormMappingConfigurationStrategy.java:271)
 at org.grails.datastore.mapping.model.config.GormMappingConfigurationStrategy.getOwningEntities(GormMappingConfigurationStrategy.java:716)
 at org.grails.datastore.mapping.model.AbstractPersistentEntity.initialize(AbstractPersistentEntity.java:79)
 at org.grails.datastore.mapping.model.AbstractMappingContext.addPersistentEntityInternal(AbstractMappingContext.java:150)
 at org.grails.datastore.mapping.model.AbstractMappingContext.addPersistentEntity(AbstractMappingContext.java:135)
 at grails.test.mixin.domain.DomainClassUnitTestMixin.mockDomain(DomainClassUnitTestMixin.groovy:124)
 at grails.test.mixin.domain.DomainClassUnitTestMixin.mockDomain(DomainClassUnitTestMixin.groovy:120)
| Failure:  validateDate(grailsshop.ShipmentTests)
|  java.lang.NullPointerException
 at org.grails.datastore.mapping.core.DatastoreUtils.unbindSession(DatastoreUtils.java:362)
 at grails.test.mixin.domain.DomainClassUnitTestMixin.shutdownDatastoreImplementation(DomainClassUnitTestMixin.groovy:109)
| Running 3 unit tests... 2 of 3
| Failure:  validateOrder(grailsshop.ShipmentTests)
|  Assertion failed:

assert shipment.errors[object] == 'nullable'
       |        |     ||       |
       |        |     |order   false
       |        |     null
       |        org.codehaus.groovy.grails.plugins.testing.GrailsMockErrors: 1 errors
       |        Field error in object 'grailsshop.Shipment' on field 'date': rejected value [null]; codes [grailsshop.Shipment.date.nullable.error.grailsshop.Shipment.date,grailsshop.Shipment.date.nullable.error.date,grailsshop.Shipment.date.nullable.error.java.util.Date,grailsshop.Shipment.date.nullable.error,shipment.date.nullable.error.grailsshop.Shipment.date,shipment.date.nullable.error.date,shipment.date.nullable.error.java.util.Date,shipment.date.nullable.error,grailsshop.Shipment.date.nullable.grailsshop.Shipment.date,grailsshop.Shipment.date.nullable.date,grailsshop.Shipment.date.nullable.java.util.Date,grailsshop.Shipment.date.nullable,shipment.date.nullable.grailsshop.Shipment.date,shipment.date.nullable.date,shipment.date.nullable.java.util.Date,shipment.date.nullable,nullable.grailsshop.Shipment.date,nullable.date,nullable.java.util.Date,nullable]; arguments [date,class grailsshop.Shipment]; default message [Property [{0}] of class [{1}] cannot be null]
       grailsshop.Shipment : null

 at grailsshop.ShipmentTests.validateOrder(ShipmentTests.groovy:39)
| Completed 3 unit tests, 3 failed in 75ms
| Packaging Grails application.....
| Compiling 1 source files.
grails>


なんか、関係のないvalidateDateまで落ちてしまいました(´・ω・`)

このあたりはGrailsの改善に期待するしかなさそうです…

テストが通るように実装をします。

Shipment.groovy

class Shipment {

    /**
     * 出荷日付.
     */
    Date date

    static belongsTo = [
            /**
             * 発注.
             */
            order : Order
    ]

    static constraints = {
        date(max: new Date())
    }
}



実装したら、テストを実行します。


grails> test-app grailsshop.Shipment
| Completed 3 unit tests, 0 failed in 168ms
| Tests PASSED - view reports in target/test-reports
grails>


今回はすんなり通りました。何だったんでしょう?あの落ちっぷりは…



さて、Warehouseの方も同様にテスト、実装します。

ShipmentTests.groovy

@TestFor(Shipment)
class ShipmentTests {

    @Test
    void validateWarehouse() {
        mockForConstraintsTests(Shipment)
        def object = 'warehouse'

        def shipment = new Shipment()
        assert shipment.validate() == false
        assert shipment.errors[object] == 'nullable'
    }
}


Shipment.groovy

class Shipment {

    /**
     * 出荷日付.
     */
    Date date

    static belongsTo = [
            /**
             * 発注.
             */
            order : Order,

            /**
             * 倉庫.
             */
            warehouse : Warehouse
    ]

    static constraints = {
        date(max: new Date())
    }
}


結論


うむ、ほんとうは@Mockをやりたかったのだが、書いている量が半端なくなってきたので、次回に…