亀岡的プログラマ日記

京都のベッドタウン、亀岡よりだらだらとお送りいたします。

NaturalSpecを使ってC#のテストコードを書いてみた。 #FsAdventJP

この記事はF# Advent Calender 2012の7日目です。はい。細かい投稿時間とか見ちゃダメです。7日目だってば。

まずは見苦しく言い訳から。

雑音は聞いたら負け、と思い本日までの記事はアーアー聞こえない(∩ ゚д゚)アーアーきこえなーいしてたのですが、投稿前にチラッと見たらもう胃が痛いのなんのってヤバすぎです。というか・・・ガブさんとネタがダダかぶりすぎてもうどうしていいのやら。

というわけで今年に入って方面からの刺激を受け、F#を本格的に勉強はじめまして。でもホント、まだまだです。なので相変わらず初心者向けというか初心者からのこんなん書いてるよ!という報告みたいなものです。

NaturalSpecに惚れたのです。

F#の存在は前々から知ってはいましたが、なんとなく自分とは縁遠い言語だとおもい、スルーしてきました。そんななかTDDに興味を持ち始めたあたりで知ったのがNaturalSpecでした。とにかく、インストールするとさらっと入っている例のリストのテストコードにやられてしまったのです。

[<Scenario>]
let ``When removing an element from a list it should not contain the element``() =
  Given [1;2;3;4;5]                 // "Arrange" test context
    |> When removing 3              // "Act"
    |> It shouldn't contain 3       // "Assert"
    |> It should contain 4          // another assertion
    |> It should have (Length 4)    // Assertion for length
    |> It shouldn't have Duplicates // Tests if the context contains duplicates
    |> Verify                       // Verify scenario

そして上記コードの詳細を含むチュートリアルについて、@smallgeekさんが訳された素晴らしいエントリーがあります。

とにかく使ってみたかった。。。

それじゃあこれでF#書くよ!と言いたいところだったのですが、、、なかなかF#本体の勉強は思うように進まず、そんななかオンラインコードレビュー勉強会である#あーだCoderが始まりました。お題はTDDBCお馴染みの自動販売機です。

そいじゃ、これのテストをF#で書いてTDDしてみるか!というのが始まりでした。本体コードはとりあえずC#で。この形式はチュートリアルでも紹介してあるので、サンプル読みながらいけるだろう!とその時は思っていたのです。。。

俺がC#でテストがF#で。

状態だけが変わるもののテストってどうすれば???

というわけで書き始めました。でもしょっぱなからよーわからんくなってきます。例えば初期状態からお金が入れられて入れられた分のお金だけ持っている、というテストの場合・・・Arrange、Act、Assertに当てはめると、

  1. 自動販売機オブジェクトを初期化する(Arrange)
  2. 自動販売機オブジェクトにお金を入れて(Act)
  3. 自動販売機の内部金額が変更されている。(Assert)

というふうに変わると考えました。。内部状態が変更しちゃっているイメージですね。
そしてNaturalSpecでは、テスト対象はパイプでつながって落ちてくるわけなので、

自動販売機オブジェクト ーArrange(初期化)ー>
自動販売機オブジェクト(初期化済み)―Act(お金を入れる)ー>
自動販売機オブジェクト(お金投入済み)―Assert(お金が入っているかどうか確認)
ー> OK or FAIL

となるのかな、と考えました。

しかし、そうなるとAssert系のメソッドの中に、『受け取ったオブジェクトのあるプロパティが望んだ値と一致している』というのを確認するメソッドが欲しくなります。それが・・・見つけられなかったのです。

あえて使えそうなメソッドをあげるなら haveメソッドです。こいつは任意のf(a -> bool)な関数とその関数に渡すa型の引数を受け取り、関数の評価結果に合わせたAssertを行なってくれます。なので、例えば以下のようにヘルパを用意すれば、結果の関数はほぼ綺麗に読み下せるような形に出来ます。

というわけで、テストできました。やったね!!よし、ヘルパメソッド書きまくってバリバリテストだ!!!!!!1111!!!!

そして賢者モード

ふぅ。。。

というわけでこんなコード出来ましたよ!

いろふさん「いや後半は読みやすくていいんやけど、前半これだけヘルパメソッドあるのはちょっと・・・」

Posaune「」

(´・ω・`)´・ω・`)´・ω・`)ジェットストリームショボーン

果たして、これ、これでいいんでしょうか・・・?

一応言っておくと、F#の諸処の定義の軽量さもあって、そんなに言うほど詰まるわけではありません。でもやはり、強引にギャップを埋めている感は出てしまいます。試みとしては楽しいのでしょうが、実用性という意味で自分の中で答えが出ていません。

そんなわけで。

恥は晒したので、みなさん暖かかったり鋭かったり厳しかったり生暖かったりするアドバイスを下さると幸いです。
特に、

C#のテストをNaturalSpecで書く是非

もっとうまい書き方はできないのか

あたり、本気でわかっていないのです。

そんなわけで、皆さんに助けを求めて終わる斬新なAdventCalenderをお送りしました。

明日はNaturalSpecチュートリアルの訳者@Smallgeekさんの「Mono for Android」ネタです。楽しみですね!!