読者です 読者をやめる 読者になる 読者になる

マイナー言語のTDDのキホン

ども, @nobkzでつ。

マイナー言語のTDDのキホン

はじめに

この記事はソフトウェアテストあどべんとかれんだー2014の2日目の記事です。

明日は@ntddkさんの「concolic testingとかそのあたり」になります。

ソフトウェアテストあどべんとかれんだー2014 - connpass

はいはい、ども言語オタクのnobkzでつ。マイナー言語でTDDするときどうするか?って話をします。

マイナー言語でTDD するときのおこりがちの問題点と解決

そもそもテストフレームワークツールなんてねーよ!

はい、まぁ、とは言っても大抵の言語なら、テストフレームワークがあるんですが、マイナーな言語はありません。というか、テストフレームワークがある言語はメジャー言語です!!!!!1

解決策:無ければ作れ!!

マイナー言語のTDDサイクル

注意:事例はSchemeで書きます!

一応、マイナー言語を選択しようと思いましたが、記法が特殊なのが多く、読者に新しい言語を覚えさせるのはどうか?と思いまして、まともなエンジニアであれば、やっているであろう、超絶メジャーな実用性の高い言語、Scheme選択します。

え? Schemeやってないんだって? 似非エンジニアが!!!!!!!!!

とりあえず、なんとなくFizzBuzzを事例にします!

とくに理由はないが、Fizzbuzzで、TDDサイクルで書いてみる

第一段階:テストコードを書く

さてさて、テストコードを書きましょう。

((fizzbuzz 1) is 1)

第二段階: REDにする。

redにしましょう。

まずは、テストコードを実行させないといけないので、テストコードをまずデータ化します。Lisp以外の言語であれば、文字列化しましょう。

"((fizzbuzz 1) is 1)”

そしてパーサーでも書いてくだしあ。

(run-test "((fizzbuzz 1) is 1)")

まぁ、これをパースして、実行する関数run-testを書くだけです!ね? 簡単でしょ?

まぁ、Lispの場合はただ単にquoteしておきましょう。

`((fizzbuzz 1) is 1)

そして、run-testを書きましょう

;; evalを使うが、ここでは環境指定子は適切に選択されているとする
(define (run-test test-code)
  (let ([subject (eval (car test-code) my-module)]
        [expected (eval (caddr test-code) my-module)])
    (display test-code)
    (display " is ")
    (if (eq? subject expected)
        (display "green!")
        (display "red!"))
    (newline)))

んで、テストを実行するため、テキトーにfizzbuzz関数を実装します。

(define (fizzbuzz x) ())

実行しましょう。

gosh>> (run-test ((fizbuzz 1) is 1))
((fizzbuzz 1) is 1) is red!

赤いですね。

第二段階:グリーンにする。

はいはい、緑にすれば良いんですよね?

(define (fizzbuzz x) 1)

実行しましょう。

gosh>> (run-test ((fizbuzz 1) is 1))
((fizzbuzz 1) is 1) is green!

やったね。緑色。

第三段階:リファクタリング

重複コードはねぇよ。

第四段階:新たにREDになるテストを書く

(run-test ((fizzbuzz 1) is 1))
(run-test ((fizzbuzz 2) is 2))

実行

gosh>> (run-test ((fizbuzz 1) is 1))
((fizzbuzz 1) is 1) is green!
((fizzbuzz 2) is 2) is red!

まぁ、赤くなりました。

第5段階:緑にする

はいはい、

(define (fizzbuzz n) n)

第6段階リファクタリング

テストコードが重複しているので、まとめましょう。

(map run-test '[((fizzbuzz 1) is 1) 
                        ((fizzbuzz 2) is 2)])

まとめ。

テストフレームワークを作れ!