ラベル 開発ツール の投稿を表示しています。 すべての投稿を表示
ラベル 開発ツール の投稿を表示しています。 すべての投稿を表示

2012年12月8日土曜日

Spring Rooをdisる

日本にはSpring Userがたくさんいるはずなんですが、

『Spring Framework Advent Calendar 2012』

知っている人がすくないのか、

職業PGのためSpringがよくわかってない人が多いのか、

なんなのかわかりませんが、2巡目書きます。

なお、昨日は@two_packさんのエントリーでした(2巡目)。


本日のお題


前回はSpring Rooを持ち上げたので、

今日はSpring Rooをこき下ろします。


IDEの導入


さて、皆さんJavaで開発する場合はIntelliJ IDEAを使っていると思いますが、

Eclipseで開発したい人も居ますよね。

まあ、そういう人は次の書籍を読んで、

Spring Rooプロジェクトを取り込む方法を

探して下さい。





IntelliJ IDEAではpom.xmlをそのまま取り込むことができるので、

Spring Rooが自動的に生成したpom.xmlを読み込むことができます。


IntelliJ IDEAをたちあげて、「Open Project」を選択します。




つぎに、Spring Rooが生成したpom.xmlを開きます。




すると、プロジェクトが自動的に開きます。





さて、この画面が表示された後に、

SpringとJPAのフレームワークが検出されたというメッセージが表示されるので、

設定してあげて下さい。


設定方法は、OKボタンを押すだけです。


disりますよ


Spring Rooというのはプログラミングレスと前回言いましたが、

本当はプログラミングが必要です。


一応、Spring RooはGrailsと違って、Java知っているだけで出来ますよってのがウリです。

でも、生成されたソースを見ると、

AspectJだらけです。






もし、何かしら特殊なことがやりたかったら、

push inする必要があります。


そのあたりはこの辺のエントリーを見て下さい。



プログラミングレスおじさん


某私が前の前の会社にいた時に、

いたんですね。プログラミングレスおじさん。


そんなおじさんにJavaなんて言おうものなら、

稟議を却下されます。


AspectJなんて言ったら、

多分「なんだそれは、どこかの会社の変なフレームワークじゃないのか?」と

稟議が却下されます。


そんな状況で、Spring rooはプログラミングレスでいいですよ

なんて言ったら、稟議が通りますが、

その後にAspectJのプッシュインとかで、

AspectJを知らない職業プログラマーが泣きを見ることは

必至です。


だから、AspectJを知らないプログラマーがいる場合は、

Spring Rooを使わないようにしましょう。



はて


明日の『Spring Framework Advent Calendar 2012』は、誰ですかね…


う~ん、代打オレといきたいけど、ちょっと今日は用事があるので、誰かおねがいします。




HipChat使おうぜい

ますます盛況を迎えるAtlassian Advent Calendar

ピンチヒッターということで、8日目を僕が書きます。

昨日は@mike_neckさんの「Atlassian on Demand使いたいぞ」でした。




使えばいいのに、馬鹿じゃないの…





す、すんません(´・ω・`)


HipChat


僕は結構Atlassianのページをよく観察していて、

これ面白そうだな~とかいろいろとブツクサつぶやいています。

でも、それほど魅力の高い製品が多いんです。

そんなかで、8月頃、HipChatなる製品を発見しました。

まあ、簡単に言えばLingrとほぼ同じものですね。


これ、便利なのは、動画の貼り付け、ファイルの送りつけ、画像の貼り付け、誰がログインしているかすぐわかる、UIはLingrの比じゃないといったあたりです。

あ、Lingrのユーザーの皆さんごめんなさい。


料金体系


1ユーザーあたり月額2USDです。

一日に会議を2時間もやっている

プロジェクトなんかにはうってつけですね。


なお、iPhone、Androidにもクライアントがあるので、

出先でも十分使えます。


というわけで、みんなHipChatやろうず


ってことでいいかな…


明日の「Atlassian Advent Calendar」ですが、

@bohnenさんのBonfireについてです。

乞うご期待!







2012年8月9日木曜日

山ライオンでmac portsがうまく動かなんだが…

こんちわ。

最近、やっとObj-Cを始めてみたみけです。

ふとしたきっかけで


最近ふとしたきっかけというよりは、

mac portコマンドを打ったら、

selfupdateしろと怒られたので、

> sudo port selfupdate
をしたのですが、

Error: 
Error: No valid Xcode installation is properly selected.
Error: Please use xcode-select to select an Xcode installation:
Error:     sudo xcode-select -switch /Applications/Xcode.app/Contents/Developer # version 4.4
Error: 

こんなメッセージが出て、

何もできなくなってしまいました(´・ω・`)

ggrks


まあ、ほっといたわけですが、

どうにもこうにもmac portsを使わないわけに行かない状況に

なったので、ggrました。

「Mountain Lion で MacPorts の更新」 - 『j-mason's diary』

ありました。

どうやら、山ライオンにするとコマンドラインツールがデフォルトオフになっていて、

かつgccのライセンスに同意しないといけないらしいです。

というわけで、上記のサイトに書かれているとおりやりました。

現在、もりもりアップデートしてくれています。

オワリ


2012年6月7日木曜日

Spring Roo始めました。 その3

今日は、JSR303 (Bean Validation)の話


制約を設ける


セレブが入会する会員制クラブをつくろう!としています。

そこで、メンバーテーブルを作ります。



基本的な制約をここでかけています。

  • 名前
    • not null / 最低2文字 / 最大40文字
  • 姓名
    • not null / 最低3文字 / 最大40文字
  • 年齢
    • 最低20 / not null
  • 収入
    • not null
  • 会員登録日
    • 過去

出来上がったMembershipクラスは次のようなコードになっています。



この段階で自動生成されたテストを流します。



自動生成されたテストのデータというのは、Spring Rooが出力したテストデータ生成用のクラスMembershipDataOnDemandクラスによって作成されます。


ビジネス的な制約の導入


ところでセレブがくる会員制クラブですので、若いヤンキーニーチャンを入会させたくありません。

そこで、30歳未満の人には高めの収入(100,000ドル以上)を持っていることを制約条件に加えようと思います。

まず、テストに上の条件のユーザーの制約を書いてみます。



テストを流します。



30歳未満で収入の低い人が入会できないことを確認するテストyoungMemberCannotBeAppliedが落ちていることがわかります。

では、この条件を実装していきます。

ここで使うのがJSR303のBean Validation APIの@AssertTrueです。

@AssertTrueは指定したフィールドまたはメソッドがtrueを返すことを強制する制約です。

これを用いて条件を実装します。



では確認のためにテストを流しましょう。



追加したテストの方は通ったようですが、あれれ、自動生成されたテストは軒並み落ちていますね。

まあ、勝手に追加した条件なのでSpring Rooの方では検知できないのでしょう。よく考えればそうですね。


git


んで、よく見てみると、モデルに変更を加えた後になぜかAspectJのコードが変化しているようです。



何が変わったのでしょうか?





40文字以上だったら40文字に直してくれてたコードが、直してくれなくなっていますね。

また、年齢が20未満だったら20に直してくれていたコードが直してくれなくなっていますね。

日付についても現在より10,000,000Lだけ前に修正してくれていたコードが現在時間+αになるように変更されています。

Spring Roo君はなんてことをしてくれるんだ!


Push in


こうなったら、AspectJのコードをJavaの方にPush Inして調整する必要があるようです。

変更されてしまったメソッドにカーソルを当てた状態で、IntelliJ IDEAのRefactorメニューからPush ITDs Inを選択します。

(eclipse…知らん…)

その後、MembershipDataOnDemand.javaのPush Inされたメソッドをテストが通る(と言うよりはビジネス的に問題のないデータが提供される)ように修正します。



では再度テストを実行してみます。



はい、通りました。

結論


はい、Spring RooのBean Validation API関連の作業について見てきました。

多少面倒なところはあるもののテストデータを自動で生成してくれたり、テストを自動で生成してくれているところは助かります。

ただ、複数のフィールドにまたがるビジネス上の制約についてはRooはアホなくらい鈍感ですね。

このあたりは慣れるしかなさそうです。

2012年4月4日水曜日

IntelliJとGitの甘い関係-1

22時間単位でせいかつしているみけです。

バージョン管理


皆さんはバージョン管理に何を使っていますか?

僕は不勉強でGitをすこしかじっただけなので、

Gitを多少触れる程度です。

今日はIntelliJ IDEAのGit連携についての記事です。


デフォルトでGitサポート


IntelliJ IDEAの公式ページを見ると、

IntelliJ IDEAは有償版、無償版共にGitをサポートしているようです。

なので、特別にプラグインを入れるなどの

作業が必要ありません。


どんな感じ?


プロジェクトを作成した後に、

以下のコマンドを実行して初期化します。

$ git init

次にIntelliJ IDEAを立ち上げて

プロジェクトを開きます。


プロジェクトを開くと、右上の方にダイアログが表示されます。


右上の「Configure」というリンクをクリックすると、

設定画面が開きます。


ここで「Add root」というリンクをクリックすると、

VCS管理の対象に入ります。




ここで「OK」ボタンを押すと、

IntelliJ IDEAとGitとの連携の設定は完了です。


使ってみる


変更を加える

最新のコミットがなされている状態です。



この状態でIntelliJ IDEAの画面を見ると、

特に何もない状態となっています。




この状態から既存のコードを変更します。




青で囲った部分を見るとわかるように、

変更が加わった箇所にはマークがついて、

ファイル名の色が変わります。


git diffがデフォルトでされているわけですね。


新規ファイルを加える

Alt + Insert(MacではCtrl + N)を押してクラスファイルを追加します。




クラス名を入力します。




「OK」ボタンを押すと、Git管理下に置くかどうかダイアログが表示されます。




「Yes」ボタンを押してGit管理下に置きます。




あたらしく出来たファイルはファイル名が緑になっています。

変更したファイルとは何が違うのでしょうか?

コマンドで確認してみます。




新しく作成したファイルはインデックス上に、

変更したファイルはワークツリーにそれぞれいる状態です。


したがって、先ほどのGit管理下に置くという操作は、

git add ファイル名をした状態と同じ状態になります。


では、引き続きコーディングします。




コーディングが終わった状態です。

コマンドで状態を確認してみます。




git addした状態で、さらにワークツリーに変更が入った状態になっています。

これはIntelliJ IDEA特有の自動セーブのお陰ですね。



コミットしてみる

では、おもむろにコミットしてみます。



コミットするとIntelliJ IDEAでの表示が変わります。



先ほどまでは変更を表していた色のマークが無くなり、

Gitワークツリーとコミットが同じ状態になっていることを表すようになります。


あれ、GUIないの?


ここまでくると、GUIがあるのではないかと思われるので、

設定を探してみたいと思います。


とりあえず、先ほどのコミットにはテストがなかったので、

テストを追加します。




テストが通ったので、

メニューから VCS → Git → Commit File を選びます。




そうすると、コミット用の画面が表示されます。



これからコミットするファイルを選んで、

コメントを入力してコミットすれば完了です。

他にもimportのOptimizeや、コード分析などをコミットの前に実施してくれるようです(オプション)。




コードに問題があるとメッセージを表示してくれます。



問題箇所が表示されますので、対応します。



再度コミットをかけます。

するとコミット完了が通知されます。



まだまだ、調べると色々ありそうです。


おお、もう6時、子供は寝る時間ですね。それでは。

2012年3月9日金曜日

JavaFX + JUnit で javascriptのunit testできるようにしてやるんで、これからハマっていってやんよ - 2

どーも、季節性鬱症がかなりひどくてやる気が0なミケです。


ツイッターでJavaFXの同期がむずいとつぶやいていたら、@skrbさんから



こんなツイートをいただきました。

JavaFXとJUnitのThreadについて丁寧に解説されていて、動作できたようです。

というわけで、コピペプログラマーとしてはコピペしないわけにはいきません。

早速Jettyも使ってunit testできるようにしましょう。


@BeforeClassで起動するWebサービス


JUnitのテストコードの中でServerを持っているのが大分辛くなってきたので、

Serverのコードは外に出すことにしました。

まだ、試作段階なので、Handlerクラスなども固定でしか動きません。




一応、サーバーのアドレスとかポートも設定できるようにしておきたいので、

コンストラクターで指定できるようにはしてあります。

ただし、現段階では使っていません。


TestBrowser


JavaFXのWebEngineを使ってテストコードを走らせるクラスです。

@skrbさんのブログの内容をそのままコピーしています。

なお、一部分を変更しています。

どうやら@Testメソッドを実行時に、画面のロードが完了していないなどの同期の部分で

失敗したため、javascript上でロードしたことをマークするようにして、ロードが完了するまでは待機するように

改造してあります。




なかなか、ソースが読みづらくてごめんなさい。試作段階ということで許しておくれ。

Threadの同期と非同期は難しいですね。

@skrbさんには非常に感謝しております。



実際のテストコード


実際のテストコードです。

これは単純に数値を計算するfunctionを呼び出しているだけです。




なお、@BeforeにてApplication#launch(Class<T extends Application>, java.lang.String[])

第二引数でサーバーのURLを渡してあります。

これは、アプリケーション側でgetParameter()メソッドを使うと取得することができます。

サーバーのポートなどの問題でURLを変更することはよくあるので、

この辺は可変にしておきたかったです。



実行結果


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



お気づきな方もいると思いますが、doStringTestの方は@Ignoreしています。

これ、@Ignoreを外すと、2つ目のテストが今は動かない状態なんです。



これはTestBrowserの部分の作りがまだまだ粗いため、2つ目のテストが実行できない状態になっているからですね。

TestBrowserの起動を@BeforeClassに移動して、

@Before毎にページを読み直すような仕様に変更しようと考えています。


とりあえず、今はこんな感じです。


どうやら…


@skrbさんの周囲で、

JRubyのなひさんJenkinsの川口さんといった

錚々たる面々のお方から反応があったらしく、

意外と面白そうなプロダクトになりそうな気がしてきました。


Seleniumと比べて


SeleniumなどのUIテスト系と比べて、僕がこのFxJsJUnitでやりたかったのはjavascriptのunit testなので、

実はUIはあまり気にしていないんです。

なので、縦幅がいくつとかはあまり興味がなくて、

純粋にjavascriptの関数に対してTDDを実施していけるような状態にしたいというのが第一の目標です。

あと@skrbさんのブログにあったとおり、

GUIは別に表示しなくてもいいという点からいくと、

Seleniumのように画面がポコポコ生まれなくていいというのが強みかなと思っていたりします。

あとはwebkit搭載なので、巷に最近溢れているブラウザー(Chrome/Android用のブラウザ/Safari)に対応できるので、

モバイル系のアプリにも対応できるテストツールになりうるかもしれません。


いずれにせよ、もう少し安定して動かせるようにしたいところです。


なお、コードはgist( https://gist.github.com/2001562 )上にあげていますので、ぜひご意見等いただければ幸いです。

あと、そのうちちゃんとしたプロジェクトとしてgithubにプロジェクトを作りたいと思っています。







2012年2月25日土曜日

Gradle、ちょっと面倒な所

どうも。

ビルドツールではGradleを一押ししているのですが、
まだまだ開発中故に残念なところがあるので、
そのメモです。

Dependencyの指定にGStringが使えない




プロジェクトの依存ライブラリーを指定するときに、
同じGroupIdで同じバージョンを使うときに、
プロパティを設けておいて、
それを利用する方がのちのち便利です。

Groovyの場合、文字を展開するのに便利なGStringクラスがあり、
変数を置き換える際にそれを利用します。

というわけで、dependencyの指定にはGStringを利用したいわけです。



上記のbuild.gradleでは、
GAEのバージョンやSlim3のバージョンをプロパティに設定して利用しているわけですが、
こんな感じのエラーが発生します。



GStringStringにキャストできないということらしいです。

対策


仕方が無いので、カッコ悪いですが、toString()メソッドを利用します。



これはソースを読んで、パッチでも送りましょうかね…

Windowsでの問題


Macなら多分問題はないと思いますが、
Windowsでやっていると、
文字コードの問題が出てきます。

これについては、@nobeansさん『豆無日記』「Gradleで文字エンコーディングを指定する方法」に詳しく書かれています。

先ほどのbuild.gradleでWindowsでコンパイルする場合、こんなエラーが出ます(コードページは932、ソースはUTF-8)。



@nobeansさんのページに書かれたとおりに修正するとこんな感じのbuild.gradleファイルになります。



これで、なんとかうまく走りました。



ココらへんは、今年中にmilestoneが30くらいまでになるというGradleですので、対策してくれるんじゃないかななどと勝手に期待してみたり…


追記:2012/02/25 8:45

@orange_cloverさんからアドバイスがあったページ
『設計と実装の狭間で。』の「[Gradle]Gradleで文字エンコーディングを指定する方法」に書いてあった方法でも
エンコーディングの指定が可能なようです。



ところが、ひとつだけ残念なところが…



IntelliJ IDEAの10.5だとエラーになってしまうんですよね…

もちろん実行できますが…


2012年2月22日水曜日

MavenからGradleに移行するただひとつの理由

MavenかGradleか?

この前の日曜日、MavenかGradleかといった論争がTLを賑わしていました。


Gradleがいいよとか、Mavenがいいよとか、Ivyだよとか、sbtだよとか、やっぱここは老舗のAntだとか…

Gradle一押しのオレの意見


MavenからGradleへ移行するたった一つの理由










それは











特にない




Mavenでちゃんとビルドができているプロジェクト、それでいいんじゃない。
それで顧客に価値が提供できているという時点で、Mavenは大きな貢献をしていると思います。

Gradleでビルドができているプロジェクト、それでいいんじゃない。
SpringとかHibernateなんかがそうです。
それで顧客に価値が提供できているという時点で、Gradleは大きな貢献をしていると思います。

だから、そういうプロジェクトがMavenからGradleへ無理に移行することもとくにないと思うし、GradleからMavenへも然り。

Mavenのpom.xml読みづらいけど、IntelliJ IDEAで読めば、結構読める。
そもそもpom.xmlわかりづらいっていう問題は、数カ月努力すれば読めるようになる。
これはオレの経験則から。
Antのbuild.xmlよりはわかりやすいですよ。pom.xml。


GradleやMavenを本当に導入するべきプロジェクトというのは、

開発者各自がjarとかzipとかをダウンロードしたり、特定の端末でないと商用ビルドができないとか、特定の担当者がいないとビルドができないとかそういう属人的、属端末的、個々人がバラバラ的なプロジェクト、そういうプロジェクトにこそ導入するべきだと思うわけです。

その意味で、
@ikeike443さんのツイート「ライブラリを探すのに未だにGoogleで検索して適当に見つかったものを手でダウンロードして、依存関係は手と目で一生懸命さがして解決して、みたいにやってる方いるもんなあ。プロダクションではまたバージョンの違う組み合わせのライブラリを使ってて動かないみたいな。」が最も的を得ていると思いました。


というわけで、多分世の中にたくさんあるであろう各自が勝手にライブラリーを落としてきて自分とこだけうまくいくようなプロジェクトにこそ、Mavenは導入してもらいたいし、Gradleは導入してもらいたい。

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をやりたかったのだが、書いている量が半端なくなってきたので、次回に…




2012年1月6日金曜日

イケてないGitの覚書き


イケてないGit覚書き


基本


コミットする



# 作業後
# コミットする
$ git commit -a -m '出版社の資本金は1円以上'
[publisher-test e93607c] 出版社の資本金は1円以上
 1 files changed, 5 insertions(+), 1 deletions(-)
$ 


変更したけどイケてないのでもとに戻す



# やらかしたので状態を取り戻す
$ git checkout filename


いや、そもそもコミットを取り消す



# やらかす
$ git commit -a -m '完璧っす'
[publisher-test f08613e3] 完璧っす
 1 files changed, 10 insertions(+), 1 deletions(-)
# あああっ!
$ git reset HEAD^


GitHubにpush



$ git push -u origin master


たくさんすることがあるとき


ブランチを作成する



$ git checkout -b publishers-attr


ブランチを移動する



$ git checkout publishers-attr


ブランチの作業結果をmasterにマージする



# 現在のブランチを確認
$ git branch
  master
* publishers-attr
# masterに戻る
$ git checkout master
# マージ
$ git merge publishers-attr


イケてないとき


ブランチで途中まで作業をしていてテストこけているのでコミットはしたくないけどこのまま作業を続けたくもない。だからMasterに戻って別の作業をしたい。



# 今のブランチ
$ git branch
  master
* publishers-attr
$ git stash
$ git checkout master
# 作業する


Masterで作業していたら閃いたので、さっきのブランチに移動してあのイケテナイ変更から再開する



$ git commit -a -m 'masterでコミット'
# 閃いた
$ git checkout publishers-attr
$ git stash pop




2011年12月31日土曜日

Confluenceをインストールしてみた。

昨日のJIRAのインストールに続き、Confluenceをインストールして見ました。

インストール手順は次のページを参照してください。(手抜き)

Confluence初心者がConfluenceインストールに挑戦してみた

インストール作業及びJIRAとの連携は思ったよりも難しくないですよ。

では、みなさん2011年も残りあと30分くらい。良いお年をおすごしください。

2011年12月11日日曜日

JIRA Advent Calendar 11日目

突然のムチャぶり


昨日の夕方頃、ベトナムのホテルでだらだらとしていたときにこんなツイートが…


yuskey
山本裕介

@mike_neck 明日 #jiraadvent がんばってください atnd.org/events/22899 /cc @Sean_SF


ん、オレ、まだJIRA買っていないんだが…困ったな。

で、よく見ると順番が大貫さんの次になっているし、エントリー内容もみんなレベル高い(・_・;)

すごい困った。





まあいいか。

JIRA Advent Calendarなのですが、あえてここでは、Confluenceの話でもしようかなと思います。

題して、

Confluenceを使ってみたい!



先述の通り、まだJIRAもConfluenceも買っていないんですが、Confluenceすごい楽しそうだなと思った動画があるので、それをどうぞ。



RedmineやTracのWikiなどは、非常に使い勝手が良いのですが、図も入ったようなドキュメントを書くのには若干向いていない気がしています。
そういう場合は仕方がないということで、MS Officeなどの製品に頼るわけですが、これがまた難敵で、各自の端末で編集するのでコラボレーションが難しいと思っていたわけです。

で、この動画を見たとき、すごい高い編集性能を持ちながら、Webで共有できるという機能に驚いてしまったわけです。


さて


さて、Confluenceほんとうに使いたいなんて思っているわけで、今なら円高だから10ユーザーでも850JPY程度。
JIRAとあわせて1,700JPY、ついでだからAtlassian Universityで習いつつやるということで、申し込んでも3,400JPY。

意外とお得かもしれません。

はい、以上、夢を語ってみました。



まあ、でもJIRAでObjective-Cの学習をチケット立てて管理するのもありだな
というわけで、来年くらいにはAmazon EC2か自宅鯖にでも導入しようと思います。

さて、次回のJIRA Advent Calendarですが、えっと、オレのムチャぶりに大人対応していただいたしょうゆさんです。

2011年10月17日月曜日

JsonSlurperを始めよう!

仕事でWebApiの設計をしているので、
JSONを扱うことが非常に多くなってきました。

ただ、JSONを扱うといっても、
ドキュメントとしてJSONのサンプルを書いているだけで、
最後、Javaに直さなければならないことを考えると、
非常に無駄の多い作業だなと思うようになってきました。

そこでGroovyですよ!


DSLを書けばいいじゃんと考えるのが普通ですよね。

ただ、まあ、そうは言ったものの、
DSLを自作できるほどのスキルも無いので、

JSONをそのままPOJOファイルに変換・出力してくれるツールをGroovyで作れないか?

と考えて見ました。

ただ(え、まだなんかあるの?)、POJOにするツールといっても、
JsonSlurperすら使い方を知らない…orz

というわけで、JsonSlurperを試しに使って見ることにしました。

SampleJsonSlurper.groovy

import groovy.json.JsonSlurper

def json = $/
{
    "getAt" : "2011/10/17",
    "person" : {
        "privateId" : 12345,
        "name" : "hoge",
        "age" : 24
    },
    "boss" : {
        "privateId" : 0,
        "name" : "Jorge",
        "age" : 41
    },
    "depart" : "sales",
    "income" : 60000,
    "projects" : [
        {
            "id" : 123,
            "name" : "Idea",
            "income" : 300000
        },
        {
            "id" : 123,
            "name" : "Idea",
            "income" : 300000
        }
    ]
}
/$

def sluper = new JsonSlurper()
def object = sluper.parseText(json)

println object.getClass()

object.each {
    println it.key
    println it.value.getClass()
}



というわけで、ComplexタイプのJSONを作ってみて、それをパースしてみました。
出力結果は次のような感じです。


class java.util.HashMap
projects
class java.util.ArrayList
person
class java.util.HashMap
depart
class java.lang.String
income
class java.lang.Integer
getAt
class java.lang.String
boss
class java.util.HashMap


どうやら、JsonSlurperparseTextは、
HashMapを返してくれて、
各値にはそれぞれ、Stringとか、ArrayListとかを
返してくれているようですね。

というわけで、JSONからPOJOを作り出すのはなんとなくできそうな気がしてきました。