Hatena::ブログ(Diary)

haru01のめも このページをアンテナに追加 RSSフィード

2014-01-25

Perl More でテストの書き方をスぶってた

参考

http://blog.ainam.me/2013/04/09/test-more-perl-testing/


use strict;
use warnings;

use Test::More 'no_plan';

subtest "array" => sub {
    my $subject;
    my $setup = sub { $subject = [1, 2, 3, 4] };
    my $teardown = sub { $subject = undef };

    subtest "pop" => sub {
        $setup->();

        my $actual1 = pop($subject);
        my $actual2 = pop($subject);
        is $actual1, 4, "配列の最後の要素がとれること";
        is $actual2, 3, "破壊メソッド";

        $teardown->();
    };


    subtest "shift" => sub {
        $setup->();

        my $actual1 = shift($subject);
        my $length = @$subject;

        is $actual1, 1, "配列の先頭要素がとれること";
        is $length, 3, "破壊メソッド";

        $teardown->();
    };
}

package FuzzBuzz;

use strict;
use warnings;
use Test::More 'no_plan';


sub fizzbuzz {
    my $array = [];
    for my $number (@_) {
        push($array, &convert($number));
    }
    return $array;
}

sub convert {
    my ($num) = @_;
    return "FizzBuzz" if($num % 15 == 0);
    return "Buzz" if($num % 5 == 0);
    return "Fizz" if($num % 3 == 0);
    return $num;
}

subtest "fizzbuzz" => sub{
    subtest "fizzbuzz配列に変換できること" => sub {
        is_deeply(&fizzbuzz(1..15),
                        [1, 2, "Fizz", 4, "Buzz",
                        "Fizz", 7, 8, "Fizz", "Buzz",
                        11, "Fizz", 13, 14, "FizzBuzz"]);
    };
};

subtest "convert" => sub {
    subtest "15の倍数はBuzzを返すこと" => sub {
        is &convert(15), 'FizzBuzz';
        is &convert(45), 'FizzBuzz';
    };

    subtest "5の倍数はBuzzを返すこと" => sub {
        is &convert(5), 'Buzz';
        is &convert(25), 'Buzz';
    };

    subtest "3の倍数はFizzを返すこと" => sub {
        is &convert(3), 'Fizz';
        is &convert(99), 'Fizz';
    };

    subtest "整数を返すこと" => sub {
        is &convert(1), 1;
        is &convert(2), 2;
        is &convert(4), 4;
    };
};

メモ

  • Perl 、 参照、配列、スカラで、変数名の付け方の$, @とかで迷う。。。
  • エラーレポートの視線の送り先のカラーリングが俺好みじゃないなぁ。
  • Test::More だと、 setup , teardown テストフレームワーク側でサポートしてないよう。
  • More以外の選択だと、Test::Classがあるもよう。

2012-12-17

TDD の素振りをしよう

このエントリは、 TDD Advent Calendar jp: 2012 : ATND の 18 日目の参加エントリです。前日のエントリは @t_wada さんの「愛せないコードを書くには人生はあまりにも短い」というタイトルで TDD について講演させていただきました #TddAdventJp #devlove2012 - t-wadaの日記でした。

ここでは TDDの素振りのススメを語っていきます。

素振り重要

おそらく、いきなり本番の仕事で、初めてTDDを実践しようにも、体や頭や心がついてこなくて、時間がかかってしまったり、フラストレーションが溜まり、やがて中断してしまうのではないでしょうか。

実際に体-頭-心が動くようになるには、普段からTDDやプログログラミングの練習、素振りが欠かせません。野球選手もいきなりバッターボックスに立つのではなく、日々の素振りやバッティング練習を行っていますが、プログラミングも同様です。プログラミング界隈で練習の重要性は、空手に例えてCode Kataとして、Dave thomas や Robert Martinなどが語っているのが知られています。

(Code Kataについて教えてくれたのは、僕が新人の頃に入社してきた kakutani さんでした。)

今日は、私も過去に行った素振り x ネット上で定番のお題を提示します。この記事の読者の何人かが、実際に体と頭と心を動かし、「TDDっていったい何だろうか?」のテーマを冬休み等を使って探求するきっかけになれば幸いです。

FizzBuzz

定番のお題ですね。ネットで調べればすぐに見つかると思います。

既に何度も解いたことがある人は、forやeachを封印してみましょう。Ruby, C#なら基本文法で対処できると思います。JavaScriptなら Underscore.js, PHPなら Underscore.php が役に立つと思います。Wikipediaに書いてある制限の「ワンライナーで解く」や「余剰(%)を使わない」などの縛りでやってみると良いでしょう。マウスは使わない、デバッカーを使わないの縛りもオススメです。Red Green Refactorで解くことも忘れないでね。

ボーリングゲームのスコア計算

定番のお題ですね

大枠の攻め方のオススメ手順は、

  • すべてガーターのスコア計算ができること
  • すべて1ピンのスコア計算ができること
  • 1フレーム目がスペアありの場合のスコア計算ができること
  • 1フレーム目がストライクの場合のスコア計算ができること
  • パーフェクトゲームのスコア計算ができること
  • その他気になるパターンを増す

をちょっとづつ解いていくです。

ポイント

ルールを知らない人は、スコア計算の方法を具体例を出して理解するところからになります。テストを書く際は、ボーリングゲームのルールが読んでわかるように記述するのがコツです。いきなり全部を解こうとせず、少しづつ解いて下さい。

既に何度か解いたことがある人は、オブジェクト指向言語を封印してTDDで解くはいかがでしょうか。個人的見解ですが、OOでボーリングを捉えることよりも、関数型でボーリングのちょっと複雑な足し算の構造に意識を集中して解く方が私は好きです。言語は、ClojureHaskell あたりはいかがでしょうか。

ライフゲーム

ライフゲームは、Coderetreat のお題にもなっています。


ポイント

ボーリングゲーム同様、ライフゲームのルールをテストで簡潔かつわかりやすく表現する方法を模索すると良いでしょう。また、Simple Ruleに注意を払いながら解いてみましょう。

既にライフゲームを解いたことがある人なら、サイトにもある縛りを増やして解いてみましょう。

私は、Immutables only の縛りでライフゲームを解くのが好きです。

数独

プログラマのためのサバイバルマニュアル」にも書かれたお題です。

ポイント

ライフゲームと同様、幾つか縛りをつけて解くと良いでしょう。Eclipse & Javaを使っているのであれば、マウスを使用せずにショートカットで、小さくリズムよく楽しくリファクタリングする指の動きの練習をするのもオススメです。私は、Eclipseリファクタリングツールが好きです。

腕に覚えがある人はぜひ「推論あり」にチャレンジしてみてはいかがでしょうか。

(私はまだ、「推論なし」しか解けていません。)

素振り中は、自分の内なる声に集中

TDDのコツの一つは「今」「Code」「私」に注目する点にあります。問題を解く際は、自分の内なる声(テストコードが語りかける声、プロダクションコードが語りかける声、実行結果の診断レポートが語りかける声)に注意を向けながら、解いてみましょう。

  • 「書いたコードや実行結果を見て、今まさに私は何を感じ-何を考え-何を発見したのだろうか?」
  • 「今からどうしたら私の気分はすっきりするのだろうか?不安は取り除けるのだろうか?」

素振りの後で、ふりかえり

素振りの後で、自分に次の問いかけをしてみましょう

  • やっている最中に自分が考えていたことは?感じていたことは?
  • Testing、Programming、Designing の活動に関する新たな(驚きの)発見は?
  • 今後、Testing、Programming、Designingする際, 試せそうなことは?

Testing、Programming、Designingに関して何か新しい発見があると幸いです。

この先は?

同じ問題をもう一度解いて、前回との違いを発見するのも良いでしょう。もっとうまく書けないか、もっとリズム良くかけないか模索してみましょう。私のお気に入りお題は、ライフゲームです。解いた後、なぜか心が晴れ晴れとした気分になれます。別のお題をKode Cataから 探すのも手です。

テスト駆動開発の本(テスト駆動開発入門, 実践テスト駆動開発 (Object Oriented SELECTION))を使って、達人のTDDの(行動|思考)過程をトレースしたり、Rails Tutorials の TDDのセクションを真似してみるのも良いかもしれません。

xUnit Patternsを使って 「そもそもテストを書く目的ってなんだろう?」「どんなところでテストにつまづくのだろう?」などなどを押さえ直すのも良いかもしれません。

TDDの外側のループの範囲をどこまでも広げて解釈し、ループをまわすのに必要な(アナログ|デジタル)ツールを素振りしてみるのも良いかもしれません。

お題は探せばいくらでも見つかります。もっと知りたいと想えば。

さいごに

自分がTDD(Testing、Programming、Designing)について、もっと知りたい!もっとうまくコードを書きたい、もっとうまくソフトウェアをつくりたい!と思えば、いつまでも-どこまでも Testing, Programming, Designing の練習し続けられます。年をとってもTDDについての何かしらの新しい-楽しい-驚きの発見があると思います。『先入観にとらわれず「どきどき-わくわく-ひやひやの驚き発見」にオープンに耳を傾け、自分の意志で次の小さな一歩を進みつづけること』こそ、TDDの(学びの)とても大切なコツだと私は考えています。

ではでは。 Happy Testing!! Happy Programming!! Happy Designing!!

次回は、@mike_neck さんの mike、mikeなるままに…: IPA 平成24年度 システムアーキテクト試験 午後2 問1 解答例 with TDDです。

2011-09-08

FIZZBUZZのテストを書き直し

(ns test.fizzbuzz
  (:use clojure.test))

(defn whole-numbers [] (iterate inc 1))
(defn fizzbuzz [num]
  (cond
    (= (rem num 15) 0) "FIZZBUZZ"
    (= (rem num 3) 0)  "FIZZ"
    (= (rem num 5) 0)  "BUZZ"
    :else              (str num)))

(deftest fizzbuzz-test
  (are [expected in] (= expected (fizzbuzz in))
    ; expected  in
      "1" 1
     "FIZZ" 3
     "4" 4
     "BUZZ" 5
     "FIZZ" 6
     "FIZZ" 9
     "BUZZ" 10
     "FIZZBUZZ" 15
     "29" 29
     "FIZZBUZZ" 30
  ))

are という文法を知った。前より簡潔になった気がする。

Data Driven Testを、JUnit でも RSpecでも簡潔かつ解りやすく書きたいんだが、未だにわかってない。

2011-09-04

Clojure テスト

(ns fizzbuzz
  (:use clojure.test))
(defn whole-numbers [] (iterate inc 1))
(defn fizzbuzz [num]
  (cond
    (= (rem num 15) 0) "FIZZBUZZ"
    (= (rem num 3) 0)  "FIZZ"
    (= (rem num 5) 0)  "BUZZ"
    :else              (str num)))

(deftest fizzbuzz-test
  (testing "FIZZBUZZ 配列を生成できること"
    (is (= (map fizzbuzz (take 15 (whole-numbers)))
            ["1" "2" "FIZZ" "4" "BUZZ" "FIZZ" "7" "8" "FIZZ" "BUZZ" "11" "FIZZ" "13" "14" "FIZZBUZZ"])))
  (testing "15の倍数は FIZZBUZZ を返すこと"
    (is (= (fizzbuzz 15)
            "FIZZBUZZ"))
    (is (= (fizzbuzz 30)
            "FIZZBUZZ")))
  (testing "3の倍数は FIZZ を返すこと"
    (is (= (fizzbuzz 3)
            "FIZZ"))
    (is (= (fizzbuzz 6)
            "FIZZ")))
  (testing "5の倍数は BUZZ を返すこと"
    (is (= (fizzbuzz  5)
            "BUZZ"))
    (is (= (fizzbuzz 10)
            "BUZZ")))
  (testing "整数を返すこと (3の倍数 5の倍数でない場合)"
    (is (= (fizzbuzz 1)
            "1"))
    (is (= (fizzbuzz 4)
            "4"))))

Clojure で テストを素振りしてみた。Clojure系なら 「数列を写像して、FIZZBUZZ 配列をつくる。ここを意識しつつ、数値を受け取ったら、数 or FIZZ or BUZZ or FIZZBUZZ を返す 関数をまずはつくる」と考えるのが筋なのかな。

ネットで調べたら、assertの仕方の練度が足りないかも。

(take 15 (whole-numbers)) とか 書いたが、rangeの方がわかりやすいか

http://softnoise.wordpress.com/2010/02/21/the-fizzbuzz-kata-in-clojure/

2007-05-10

[] Fizz Buzz take2

会社の先輩に教えてもらって、別のアプローチ。

p (1..100).map{|x| s = "#{'Fizz' if (x % 3).zero?}#{'Buzz' if (x % 5).zero?}"; s.any? ? s:x}

[] Fizz Buzz

一人でFizz Buzzと口に出してみたが、この言葉遊びゲーム、難しそうだ。

何も見ずだと100まで言えそうにない

なので、Macにしゃべらせた。

(1..100).to_a.map{|x| if (x%3==0 && x%5==0) then "FizzBuzz" elsif (x%3==0) then "Fizz" elsif(x%5==0) then "Buzz"else x end }

コマンド + F5

もっとコンパクトに書きたい。