What is it, naokirin?

テスト駆動開発の練習(10) -Erlang&eunitで足し算関数-

朝早く起きたので、少しプログラミング。

引数によって、数値同士を足し算するか、リスト同士を結合する関数を作ります。
今回は"if"とリスト同士の結合に使われる"++"、また"?_assertException"を使ってみました。

早速ソースコード。(ちなみに一ヶ所作りたい感じになっていないのですが・・・)

-module(arithmeticTest).
-export([addition/2]).
-include_lib("eunit/include/eunit.hrl").

addition(X, Y) ->
    if 
	(is_integer(X) and is_integer(Y)) or
	(is_integer(X) and is_float(Y)) or
        (is_float(X) and is_integer(Y)) or
	(is_float(X) and is_float(Y)) ->
	    X + Y;
	is_list(X) and is_list(Y) ->
	    X ++ Y
    end.


add_test_() ->
    [?_assert(addition(1,1)=:=2),
     ?_assert(addition(-1,1)=:=0),
     ?_assert((addition(1.10,2.20) < 3.31) and (addition(1.10, 2.20) > 3.29)),
     ?_assert(addition(1.1,2)=:=3.1),
     ?_assert(addition(1, 2.1)=:=3.1),
     ?_assert(addition([1,2],[3])=:=[1,2,3]),
     ?_assert(addition([],[])=:=[]),
     ?_assert(addition("Hello ", "World")=:="Hello World"),
     ?_assertException(error, if_clause, addition(1,[1])),
     ?_assertException(error, if_clause, addition([1],1)),
     ?_assertException(error, if_clause, addition(atom,1)),
     ?_assertException(error, if_clause, addition(1, atom))
    ].

arithmeticTest.erl

コードを読むと気がつくかもしれませんが、小数の足し算のテストのところが"=:=3.3"となってません。
これは実際にテストしてみるとこの部分だけテスト失敗となるため、関数を起動してみたところ、"3.3000000000000003"と表示されていました。うーん、何なんでしょうね、最後の"3"は・・・。

仕方ないので上のような判定にしています。
この辺の仕様はまだ読んでいないのでよくわからないですね。


ちなみに文字列はリストなので、文字列の結合は問題ありません。


あ、文字列とリストの結合をテストしていませんね・・・。


最近はこの小さなコードをTDDで作っている記事ばかりですね。
TDDを行いつつ自分の知らない機能やアルゴリズムの実装をしているので、TDDの習得だけのためにやっているわけではないのですが・・・。
相対論や暗号論などはもうそろそろ勉強を再開したいところです。


追記:
テストコードをテスト失敗時に結果が見やすいアサートに書き換えてみます。

add_test_() ->
    [?_assertEqual(2, addition(1,1)),
     ?_assertEqual(0, addition(-1,1)),
     ?_assertMatch(X when (X < 3.31) and (X > 3.29), addition(1.10, 2.20)),
     ?_assertEqual(3.1, addition(1.1,2)),
     ?_assertEqual(3.1, addition(1, 2.1)),
     ?_assertEqual([1,2,3], addition([1,2],[3])),
     ?_assertEqual([], addition([],[])),
     ?_assertEqual("Hello World", addition("Hello ", "World")),
     ?_assertException(error, if_clause, addition(1,[1])),
     ?_assertException(error, if_clause, addition([1],1)),
     ?_assertException(error, if_clause, addition(atom,1)),
     ?_assertException(error, if_clause, addition(1, atom))
    ].



_assertEqual()や_assertMatch()を使うことで、失敗時にactualとexpectedの値を見ることができます(だったはず)。

また、_assertMatch()を使ったことで判定が少しは見やすくなったかもしれません。


旧コメント:
丸め誤差


"3.3000000000000003"は浮動小数点計算での誤差かな?と思いつつ・・・

JUnitのassertEqualsならば
assertEquals(*expected,* actual,* delta)
のように、3つ目の引数に許容誤差をかけますが、EUnitにはなさそう?
マクロだと厳しいのでしょうかね…

2011-02-11 08:07 | pbsk


Re: 丸め誤差


> "3.3000000000000003"は浮動小数点計算での誤差かな?と思いつつ・・・
多分、誤差でしょうね。単純に足し算を実行しても起こるようなので。


> JUnitのassertEqualsならば
> assertEquals(*expected,* actual,* delta)
> のように、3つ目の引数に許容誤差をかけますが、EUnitにはなさそう?
> マクロだと厳しいのでしょうかね…
そこまでEUnitの仕様が確認できていないのが現状です。
ちなみに?_assert()ではなく、?_assertEqual()や?_assertMatch()というのも存在しますが今回は使っていません(テスト結果の情報としては?_assertEqual()や?_assertMatch()の方が多く出るので実際に使う場合はそちらの方がいいと思います)。


また調べてみました許容誤差を指定できるという内容が見つかりませんでした。無いのかもしれませんね。

2011-02-11 08:32 | Naoki Rin