ScalaでJUnitテストケースを書く
とりあえず、Scala用のテストフレームワークは使わず、素のJUnitを使った例。
Eclipseから使う場合、JUnit関連クラスのimportはクラススコープの外側に書いておかないと、右クリックからテスト実行できないようです。
あと、Scala2.8からアノテーションのパラメータの書き方が変わったようで、Javaと同じような記述ができるようになりました。(2.8で、前と同じ書き方をするとコンパイルエラーになります)
import org.junit.{ Test, After, Before } import org.junit.Assert._ class SampleTest { @Before def befor = { // 前処理 } @Test(timeout=500) //@Test{val timeout=500} //Scala2.7以前ではこう書く def testHoge = { Thread.sleep(300) assertEquals(1, 1) } @After def after = { // 後処理 } }
Scalaの文字列処理とかパターンマッチングの便利さを考えると、JavaのテストケースもScalaで書いたほうが楽かもしれない。
Monadについて
勉強中。あとでまとめる。
(2010/09/06)ざっくりまとめ
オブジェクト指向・手続き型脳味噌で理解したモナド(の概念の一部)
- モナドは、副作用の範囲を封じ込めるコンテナとして見ることができる
- 高階関数を受け取り、モナドの中身に適用して、その結果をまたモナドに詰めて返す
- 関数Aをモナドに渡し、その戻り値に関数Bを渡し、その戻り値に関数Cを渡し…と連鎖させることで、A→B→Cの評価順を確定することができる
モナドの中身を取り出すのは、Scalaではunit、Haskellではreturn←これは完全に間違い。- 値を受け取り、その値を格納したモナドのインスタンスを生成する関数を持つ(
Scalaではmap、HaskellではunitScalaではコンストラクタ、Haskellではreturn) - 関数を連鎖させた際にモナドの多重化を防ぐための仕組みが用意されている(ScalaではflatMap、Haskellではbind)
- モナドで使用する高階関数は、モナドの中身を受け取って、モナドを返す
- Scalaのfor文は、ListモナドとflatMapに展開される。
参考資料
All About Monads http://www.sampou.org/haskell/a-a-monads/html/index.html
「モナドは象だ」の翻訳まとめ - {Fight the Future => じゅくのblog} http://d.hatena.ne.jp/jyukutyo/20081111/1226392144
EclipseのJavaプロジェクトや動的WebプロジェクトでScalaソースを混在させる
「EclipseでのScala+Webアプリ開発 」の件で、とりあえずScalaコードを混ぜ込んでもビルドされるようになったので、方法の簡単に書いておきます。ただしちゃんと検証できてないので真似する際は自己責任で。
- Scala IDE for Eclipse (Scala Plugin)をインストールしておく。
- Eclipseを終了させ、対象プロジェクトのフォルダにある .project ファイルを開く。
- buildSpec要素内にある、javabuilderの設定を scalabuilderに置き換える
<!-- javabuilderをコメントアウト <buildCommand> <name>org.eclipse.jdt.core.javabuilder</name> <arguments> </arguments> </buildCommand> --> <!-- 以下追記 --> <buildCommand> <name>org.scala-ide.sdt.core.scalabuilder</name> <arguments> </arguments> </buildCommand>
- nature要素内に、scalanatureの設定を追加する。
<natures> <nature>org.eclipse.jem.workbench.JavaEMFNature</nature> <nature>org.eclipse.wst.common.modulecore.ModuleCoreNature</nature> <nature>org.eclipse.wst.common.project.facet.core.nature</nature> <nature>org.eclipse.jdt.core.javanature</nature> <nature>org.eclipse.wst.jsdt.core.jsNature</nature> <nature>org.scala-ide.sdt.core.scalanature</nature> <!-- 追記 --> </natures>
- Eclipseを起動する
scalabuilderは、Javaソースを見つけると処理をjavacに渡してくれるようなので、javabuilderはコメントアウトでOKです。
機能のテンプレ化に関する考察
大規模システムのフレームワークとか作っていると、まずは「機能の標準化」というお題目で、画面の流れのモデルケースを作り(例:検索→一覧→選択して編集→DB更新→検索画面へ戻る)、個別機能の設計ではこのモデルケースに極力準拠してもらいつつ、実装作業が始まる前にモデルケースの実装例をテンプレとして提示する、ということをよくやります。
ただ、これを素直にやっちゃうと、テンプレをコピペした機能が何十と出来上がっちゃって、標準そのもののバグや仕様変更があると莫大な修正工数がかかる、ということになりがちです。
テンプレをコピペさせるくらいなら、フレームワークのAPIに封じて、個別に書く部分(画面やSQL、独自の論理チェックなど)を極小化することを考えたほうがよいのは、ちょっと考えればわかることですね。
この辺を突き詰めたのがSpring Rooだったりするわけですが、本ブログでは、一歩下がって、「プロジェクト毎モデルケースのフレームワーク化」を容易にし、かつカスタマイズ柔軟性を確保する方向で考えてみます。ScalaにおけるTraitのしくみがうまく使えそうな予感。
フレームワークとして共通化する部分の抽出
処理の整理の段階で大体分類は終わってるんですけど、基本的には、前回([id:shout_poor:20100817#1282021845])での整理のうち、「本処理」の部分が個別ロジックとなり、それ以外のところは共通化できると考えます。
以下、切り分けが微妙な部分の検討。
入力パラメータの整合性チェック
入力パラメータのチェックは、画面ごとに設計してしまいがちですが、本来は項目の性質によって横断的に決められるものです。例えば書籍の管理コードであるISBNコードは、どの画面であっても英数13桁で入力されなければ困りますし、日付型の項目であれば、その用途に関わらず、入力形式は原則アプリケーション内で一致させた方がいいでしょう。
従って、最低限の整合性チェックは共通機能として、同じ名称の項目であれば同じチェックがかかるようにします。