Test::More、Test::Classをそれぞれ使ったテストについて調べました。
テストするモジュールは、下記のようなものです。
# 直線を表すモジュール package Line; use strict; use warnings; # 「ax + by + c = 0」の「a,b,c」部分が渡される sub new { my $class = shift; my ($a, $b, $c) = @_; bless { a => $a, b => $b, c => $c }, $class; } # 「ax + by + c = 0」の「a,b,c」部分を表示 sub to_string { my $self = shift; return "a = " . $self->{a} . ", b = " . $self->{b} . ", c = " . $self->{c}; } # 渡された直線との交点を返す sub get_intersection_point { my $self = shift; my ($l) = @_; my $d = $self->{a} * $l->{b} - $l->{a} * $self->{b}; if ($d == 0.0) { return undef; } my $x = ($self->{b} * $l->{c} - $l->{b} * $self->{c}) / $d; my $y = ($l->{a} * $self->{c} - $self->{a} * $l->{c}) / $d; return { x => $x, y => $y }; } # 2点の座標(x1, y1) (x2, y2)から直線インスタンスを作成する sub from_points { my ($x1, $y1, $x2, $y2) = @_; my $dx = $x2 - $x1; my $dy = $y2 - $y1; return Line->new($dy, -$dx, $dx * $y1 - $dy * $x1); } 1;
「ax + by + c = 0」の直線を表すモジュールです。
モジュールは「a,b,c」の値を保持していて、一つの直線を表します。
このモジュールで算出されるはずの座標は、手計算であらかじめ算出しておきます。
Test::More
下記が一連のテストの記述です。
# 00.t use strict; use Test::More; plan( tests => 8 ); # モジュール読み込みチェック use_ok("Line"); # インスタンスの確認 my $obj = Line::from_points(0, 1, 6, 4); isa_ok( $obj, 'Line' ); # メソッドが定義されているかのチェック can_ok( $obj, qw/new to_string from_points get_intersection_point/); # 期待値かどうか is( $obj->{a}, 3, '$obj->{a}が期待値と一致するか確認'); is( $obj->{b}, -6, '$obj->{b}が期待値と一致するか確認'); is( $obj->{c}, 6, '$obj->{c}が期待値と一致するか確認'); # 正規表現でチェック like( $obj->to_string(), qr/a = [\.\-0-9]+, b = [\.\-0-9]+, c = [\.\-0-9]+/, '$obj->to_string()が正規表現と一致するか確認'); my $obj2 = Line::from_points(3, 6, 5, 0); my $point = $obj->get_intersection_point($obj2); # 構造体が一致しているか is_deeply( $point, { x => 4, y => 3 }, '$pointが構造体と一致するか確認' );
上記のプログラムは「00.t」という名前で保存しました。
このテストを実行するために、proveコマンドを使用します。
proveコマンドは、「Test::Harness」をインストールすると付いてきます。
「prove -lv t/00.t」で実行すると下記のようにテストが完了します。
$ prove -lv t/00_compile.t Name "main::running_under_some_shell" used only once: possible typo at /usr/bin/prove5.10.0 line 3. t/00_compile.t .. 1..8 ok 1 - use Line; ok 2 - The object isa Line ok 3 - Line->can(...) ok 4 - $obj->{a}が期待値と一致するか確認 ok 5 - $obj->{b}が期待値と一致するか確認 ok 6 - $obj->{c}が期待値と一致するか確認 ok 7 - $obj->to_string()が正規表現と一致するか確認 ok 8 - $pointが構造体と一致するか確認 ok All tests successful. Files=1, Tests=8, 0 wallclock secs ( 0.06 usr 0.01 sys + 0.05 cusr 0.02 csys = 0.14 CPU) Result: PASS
Test::Class
Test::Classは、xUnit風にテストが書けるフレームワークです。
オブジェクト指向に書けるというだけで、Test::Moreと同じほとんど同じ感じです。
#!/usr/bin/env perl use strict; use warnings; My::Test->runtests; package My::Test; use base qw/Test::Class/; use Test::More; use Line; sub make_fixture : Test(setup) { my $self = shift; $self->{line} = Line::from_points(0, 1, 6, 4); } sub test_instance : Test(no_plan) { my $line = shift->{line}; isa_ok $line, 'Line'; ok $line->can($_) for qw/new to_string from_points get_intersection_point/; } sub test_member : Test(no_plan) { my $line = shift->{line}; is $line->{a}, 3, '$obj->{a}が期待値と一致するか確認'; is $line->{b}, -6, '$obj->{b}が期待値と一致するか確認'; is $line->{c}, 6, '$obj->{c}が期待値と一致するか確認'; } sub test_method : Test(no_plan) { my $obj = shift->{line}; like $obj->to_string(), qr/a = [\.\-0-9]+, b = [\.\-0-9]+, c = [\.\-0-9]+/, '$obj->to_string()が正規表現と一致するか確認'; my $line2 = Line::from_points(3, 6, 5, 0); my $point = $obj->get_intersection_point($line2); is_deeply $point, { x => 4, y => 3 }, '$pointが構造体と一致するか確認'; } 1;
関数の属性で「: Test(no_plan)」と書きます。
「no_plan」の場所は、テストの回数を書きますが、面倒くさいのでこうしてしまっています。
本当はいけないらしい・・・?
参考
- 作者: 牧大輔
- 出版社/メーカー: 翔泳社
- 発売日: 2009/02/10
- メディア: 大型本
- 購入: 23人 クリック: 465回
- この商品を含むブログ (112件) を見る