• Save
What is wrong on Test::More? / Test::Moreが抱える問題点とその解決策
Upcoming SlideShare
Loading in...5
×
 

What is wrong on Test::More? / Test::Moreが抱える問題点とその解決策

on

  • 3,306 views

What is wrong on and how to improve Test::More.

What is wrong on and how to improve Test::More.
Test::Moreの何が問題でどう解決すればいいか。

Statistics

Views

Total Views
3,306
Views on SlideShare
3,197
Embed Views
109

Actions

Likes
4
Downloads
0
Comments
0

4 Embeds 109

https://twitter.com 66
http://iteman.tumblr.com 29
https://si0.twimg.com 13
http://twitter.com 1

Accessibility

Categories

Upload Details

Uploaded via as Adobe PDF

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

What is wrong on Test::More? / Test::Moreが抱える問題点とその解決策 What is wrong on Test::More? / Test::Moreが抱える問題点とその解決策 Presentation Transcript

  • YAPC::ASIA 2012What is wrongon Test::More?Test::Moreが抱える問題点とその解決策makoto kuwata <kwa@kuwata-lab.com>http://www.kuwata-lab.com/2012-09-27 (Fri) copyright(c) 2012 kuwata-lab.com all rights reserved.
  • Agenda✦ Testing without spec 仕様を書かずにテストしてる✦ Not structured tests テストが構造化されてない✦ Needs test plan 事前にテストプラン (=テスト数) を必要とする✦ No fixture feature フィクスチャ機能がない✦ Hard to distinguish assertions どれがアサーションなのか分かりにくい copyright(c) 2012 kuwata-lab.com all rights reserved.
  • Section 1:Testing without spec仕様を書かずにテストしている copyright(c) 2012 kuwata-lab.com all rights reserved.
  • Point Write your test according to spec, not your code. テストは、コードではなく仕様をもとに書け。 copyright(c) 2012 kuwata-lab.com all rights reserved.
  • Sample: Test::More (Perl)use Test::More tests => 4;is f(0), 0;is f(1), 1;is f(2), 1;is f(3), 2; copyright(c) 2012 kuwata-lab.com all rights reserved.
  • Sample: RSpec (Ruby)describe f() it "calculates fibonacchi sequence" do f(0).should == 0 f(1).should == 1 f(2).should == 1 f(3).should == 2 endend copyright(c) 2012 kuwata-lab.com all rights reserved.
  • Sample: unittest (Python)import unittestclass FooTest(unittest.TestCase): def test_calculates_fiboacchi_seq(self): """Calculates Fibonacchi sequence""" self.assertEqual(0, f(0)) self.assertEqual(1, f(1)) self.assertEqual(1, f(2)) self.assertEqual(2, f(3)) copyright(c) 2012 kuwata-lab.com all rights reserved.
  • Goal of test✦ Test::More: Does that code run correctly? そのコードは意図した通りに動くか?✦ RSpec: Does that code satisfy the spec? そのコードは仕様を満たしているか? copyright(c) 2012 kuwata-lab.com all rights reserved.
  • Difference between Test::More and RSpec## Test::Morelike $html, qr<h3>Hello</h3>; Higher-level information より高水準の情報## RSpecit "contains section title" do html.should =~ %r<h3>Hello</h3>end copyright(c) 2012 kuwata-lab.com all rights reserved.
  • Solution: spec() https://gist.github.com/3797929sub spec { my ($text, $block) = @_; $block->();}## usagespec "page contains section title", sub { ok(render() =~ qr`<h1>Hello</h1>`);}; copyright(c) 2012 kuwata-lab.com all rights reserved.
  • Spec FirstStep 1. Write specificationsspec "...specification1...";spec "...specification2..."; #=> not ok 1 - ...spec... # TODO #=> not ok 2 - ...spec... # TODOStep 2. Add assertions according to specspec "...specification...", sub { assertion1; assertion2;}; copyright(c) 2012 kuwata-lab.com all rights reserved.
  • Solution: spec() https://gist.github.com/3797939sub spec { my ($text, $block) = @_; return $block->() if $block; TODO: { local $TODO = ": not implemented yet"; ok(undef); }} copyright(c) 2012 kuwata-lab.com all rights reserved.
  • Meaning of output linesAs is - ok when assertion passed, not ok when failed アサーションが成功したらok、失敗したらnot okok 1 - assertion1not ok 2 - assertion2To be - ok when spec satisfied, not ok when not コードが仕様を満たしたらok、満たさなければnot okok 1 - specification1not ok 2 - specification2 copyright(c) 2012 kuwata-lab.com all rights reserved.
  • Spec : Assertion = 1 : N✦A specification can contain some assertions 1つの仕様に複数のアサーションを書いてよいspec "returns pair of integer", sub { is scalar(@$ret), 2; like $ret->[0], qr/^d+$/; like $ret->[1], qr/^d+$/;}; copyright(c) 2012 kuwata-lab.com all rights reserved.
  • Spec : Assertion = 1 : NAs is Output lines per assertion アサーションごとに出力行ok 1ok 2ok 3To beok 1 - returns pair of integer Output lines per spec 仕様ごとに出力行 copyright(c) 2012 kuwata-lab.com all rights reserved.
  • Solution: OK() https://gist.github.com/3797954sub OK { my ($expr) = @_; unless ($expr) { my ($pkg, $file, $lineno) = caller(); die "AssertionFailed" ." at $file line $lineno.n"; }} copyright(c) 2012 kuwata-lab.com all rights reserved.
  • Solution: spec() https://gist.github.com/3797954my $spec = undef;my $num = 0;sub spec { my ($text, $block) = @_; $spec = $text; $num++; eval { $block->(); }; my $err = $@; if (! $err) { print "ok $num - $textn"; } else { print "not ok $num - $textn"; $err =~ s/^/# /mg; $err .= "n" if $err !~ /nz/; print STDERR $err; }} copyright(c) 2012 kuwata-lab.com all rights reserved.
  • Conclusion of this section✦ Write test based on spec, not on code テストは、コードに対してではなく、仕様に対して書く✦ Spec specified? instead of Run correctly? 「正しく動作するか?」ではなく「仕様を満たしているか?」✦ Spec first, assertion second 仕様を先に書いて、そのあとにアサーションを書く✦ Spec : Assertion = 1 : N 1つの仕様が複数のアサーションを含んでよい✦ Output line per spec, not assertion 出力行のok / not okはアサーション単位ではなく仕様単位に出す copyright(c) 2012 kuwata-lab.com all rights reserved.
  • Section 2:Not structured testsテストが構造化されてない copyright(c) 2012 kuwata-lab.com all rights reserved.
  • PointTest should have structure.Because spec has structure.テストには構造がある。なぜなら仕様に構造があるから。 copyright(c) 2012 kuwata-lab.com all rights reserved.
  • Sample: Specification document クラス:Calendar メソッド:isLeapYear(int year): boolean 動作詳細: ・100で割り切れる場合、 ・400で割り切れる場合はtrueを返す ・それ以外はfalseを返す ・4で割り切れる場合はtrueを返す ・それ以外はfalseを返す copyright(c) 2012 kuwata-lab.com all rights reserved.
  • Test code as spec documentIs your test code availableas spec document?そのコードは仕様書としてほんとに利用できるの? copyright(c) 2012 kuwata-lab.com all rights reserved.
  • Sample: Test::Moreuse Test::More tests => 2;use Foo;$foo = Foo->new();is(Foo->new()->meth1(), 11);is(Foo->new()->meth2(), 12); copyright(c) 2012 kuwata-lab.com all rights reserved.
  • Sample: RSpec Test target (class, method, ...)require rspec テスト対象 (クラス、メソッド、…)describe Foo do describe #bar() do context when arg is provided do it "returns length" do Foo.new.methd1([0,1,2]).should == 3 Foo.new.methd1([]).should == 0 end end endend copyright(c) 2012 kuwata-lab.com all rights reserved.
  • Sample: RSpec Test condition or situationrequire rspec 条件や状況describe Foo do describe #bar() do context when arg is provided do it "returns length" do Foo.new.methd1([0,1,2]).should == 3 Foo.new.methd1([]).should == 0 end end endend copyright(c) 2012 kuwata-lab.com all rights reserved.
  • Sample: RSpecrequire rspecdescribe Foo do describe #bar() do context when arg is provided do it "returns length" do Foo.new.methd1([0,1,2]).should == 3 Foo.new.methd1([]).should == 0 end end end Specification 仕様end copyright(c) 2012 kuwata-lab.com all rights reserved.
  • Sample: unittest (Python)import unittestclass FooTest(unitteset.TestCase): def test_bar_1(self): """returns length of arg passed""" self.assertequal(3, Foo().bar([1,2,3])) def test_bar_2(self): """returns 0 when arg is not passed""" self.assertEqual(0, Foo().bar()) copyright(c) 2012 kuwata-lab.com all rights reserved.
  • Sample: Test::Unit2 (Ruby)require test/unitrequire fooclass FooTest < Test::Unit::TestCase class MethTest < self def test_returns_length_of_arg n = Foo.new.bar([1,2,3]) assert_equal 3, n end endend ref: http://www.clear-code.com/blog/2012/4/25.html copyright(c) 2012 kuwata-lab.com all rights reserved.
  • Sample: subtest() (Test::More)use Test::More tests=>1;subtest "package Foo", sub { plan tests=>1; subtest "sub bar()", sub { plan tests=>2; ok (1+1 == 2); ok (1-1 == 0); };}; copyright(c) 2012 kuwata-lab.com all rights reserved.
  • Sample: subtest() (Test::More)$ perl homhom.t1..1 1..1 1..2 ok 1 ok 2 ok 1 - sub bar()ok 1 - package Foo copyright(c) 2012 kuwata-lab.com all rights reserved.
  • Sample: subtest() (Test::More)$ perl homhom.t1..1 1..1 1..2 ok 1 ok 2 ok 1 - sub bar()ok 1 - package Foo copyright(c) 2012 kuwata-lab.com all rights reserved.
  • Sample: subtest() (Test::More)$ perl homhom.t1..1 1..1 1..2 ok 1 ok 2 ok 1 - sub bar()ok 1 - package Foo copyright(c) 2012 kuwata-lab.com all rights reserved.
  • Solution: subtest() alternatives Test target テスト対象print "1..2n";topic package Foo, sub { topic sub meth1(), sub { case_when arg is passed, sub { spec "1+1 should be 2", sub { OK(1+1 == 2); }; spec "1-1 should be 0", sub { OK(1-1 == 0); }; }; Condition or situation }; 条件や状況}; copyright(c) 2012 kuwata-lab.com all rights reserved.
  • Solution: subtest() alternatives$ perl homhom.t1..2# * package Foo# * sub meth1()# - when arg is passedok 1 - 1+1 should be 2ok 2 - 1-1 should be 0 copyright(c) 2012 kuwata-lab.com all rights reserved.
  • Solution: subtest() alternatives https://gist.github.com/3797976my $depth = 0;sub topic { my ($name, $block) = @_; my $indent = x $depth; print "# $indent* $namen"; $depth++; $block->(); $depth--;} copyright(c) 2012 kuwata-lab.com all rights reserved.
  • Solution: subtest() alternatives https://gist.github.com/3797976my $depth = 0;sub case_when { my ($condition, $block) = @_; my $indent = x $depth; print "# $indent- $conditionn"; $depth++; $block->(); $depth--;} copyright(c) 2012 kuwata-lab.com all rights reserved.
  • Conclution of this section✦ Testhas structure, because spec has structure. テストには構造がある。なぜなら仕様に構造があるから。✦ xUnit focuses on test automation, RSpec focuses on test structure. xUnitは自動化のための道具、RSpecは構造化のための道具✦ Output of subtest() suck. Define your own subtest alternatives. subtest()は出力が残念すぎる。自前関数お勧め。 copyright(c) 2012 kuwata-lab.com all rights reserved.
  • Section 3:Needs test plan事前にテストプラン (=テスト数) を必要とする copyright(c) 2012 kuwata-lab.com all rights reserved.
  • Sample: Test::Moreuse Test::More tests=>2;is(1+1, 2);is(1-1, 0);$ perl homhom.t1..2ok 1ok 2 copyright(c) 2012 kuwata-lab.com all rights reserved.
  • Sample: subtest()use Test::More tests=>1;subtest package Foo, sub { plan tests=>1; subtest sub meth(), sub { plan test2=>1; is(1+1, 2); is(1-1, 0); };}; copyright(c) 2012 kuwata-lab.com all rights reserved.
  • Pros of test plan✦ Detect unexpected test finishing テストの異常終了が検知できる • Compare number of (ok + not ok) with test plan 出力されたokやnot okの数と、 宣言されたテスト個数とを比較✦ Necessary to report test progress テスト実行時に進行状況を知るのに必要 • Especially for prove command 特にproveコマンドで copyright(c) 2012 kuwata-lab.com all rights reserved.
  • Cons of test plan✦ Too messy to keep currect value 正しい値に更新し続けるのが面倒すぎる • Update test plan when you add assertions assertion関数を追加したら忘れずに更新 • back to top when you add at the end of file ファイルの末尾にテストを追加したら、先頭に戻ってテスト数 を更新 copyright(c) 2012 kuwata-lab.com all rights reserved.
  • Sample: done_testing()use Test::More tests=>2;is(1+1, 2);is(1-1, 0);done_testing();$ perl homhom.tok 1ok 21..2 copyright(c) 2012 kuwata-lab.com all rights reserved.
  • done_testing() and subtest()use Test::More tests=>1;subtest "package Foo", sub { subtest "sub meth1()", sub { ok (1+1 == 2); ok (1-1 == 0); done_testing(); }; done_testing();};done_testing(); (No need to call done_testing() in subtest() since Test::More 0.95_01) copyright(c) 2012 kuwata-lab.com all rights reserved.
  • Solution: subtest() alternatives$ perl homhom.pl ok 1 ok 2 1..2 ok 1 - sub meth1() 1..1ok 1 - package Foo1..1 copyright(c) 2012 kuwata-lab.com all rights reserved.
  • Pros of done_testing()✦ No need to speicfy test plan! テスト数を指定しなくていい! copyright(c) 2012 kuwata-lab.com all rights reserved.
  • Cons of done_testing()✦ Need to expand TAP spec TAP仕様に拡張が必要 • Simplicity of TAP has gone もはやTAPの簡易性は損なわれた✦ Prove prints ? as number of tests proveコマンドで全体のテスト数が「?」に • Degeneration of interface インターフェースとしては退化 copyright(c) 2012 kuwata-lab.com all rights reserved.
  • Off Topic: Doubt about TAP✦ If TAP accepts test plan after running tests, テスト数がわかるのがテスト終了後でいいなら • End of test indicatior is necessary for TAP, but test plan is not, is it? テストの終わりが分かる何かがあればテスト数いらなくね? • Index number of test is not necessary, is it? そもそも ok や not ok に通し番号いらなくね? ok 1 # ..spec.. ok 2 # ..spec.. <<TEST END>> copyright(c) 2012 kuwata-lab.com all rights reserved.
  • The root cause of problem✦ Impossibleto count number of tests before running tests テスト数を事前に数えられない✦ To be あるべき姿 • Step1. Count and print number of tests テスト数を数えて出力 • Step2. Run tests テストを実行 copyright(c) 2012 kuwata-lab.com all rights reserved.
  • Solution: Intermediate data structureAs is:is 1+1, 2; ok 1is 1-1, 0; ok 2 1..2To be: topicis 1+1, 2; topic 1..2is 1-1, 0; ok 1 spec ok 2 spec Easy to count tests copyright(c) 2012 kuwata-lab.com all rights reserved.
  • Cons of intermediate data structure✦ Easyto count and filter tests before running tests テスト実行前にテストを数えたりフィルタするのが簡単にできる✦ No need to extend TAP specification TAPの仕様を拡張しなくてよい • No more done_testing() done_testing()なんていらない • No more nesting like subtest() subtest()のような入れ子対応はいらない copyright(c) 2012 kuwata-lab.com all rights reserved.
  • Sample: xUnitclass FooTest(TestCase): def test1(self): ... def test2(self): ...## build intermediate data structuresuite = TestSuite()suite.add(FooTest(test1))suite.add(FooTest(test2))## run testsTestRunner().run(suite) copyright(c) 2012 kuwata-lab.com all rights reserved.
  • Solution: topic() and spec() https://gist.github.com/3798000topic class Foo, sub { topic sub meth1(), sub { case_when "arg is given", sub { spec "1+1 should be 2", sub { OK(1+1 == 2); }; }; Change to build tree };}; Traverse treerun_all(); copyright(c) 2012 kuwata-lab.com all rights reserved.
  • Solution: topic() https://gist.github.com/3798000my $NODES = [];sub topic { my ($name, $block) = @_; my $node = {name=>$name, prefix=>*, children=>[]}; push @$NODES, $node; my $bkup = $NODES; $NODES = $node->{children}; $block->(); $NODES = $bkup;} copyright(c) 2012 kuwata-lab.com all rights reserved.
  • Solution: spec() https://gist.github.com/3798000my $NODES = [];sub spec { my ($text, $block) = @_; push @$NODES, [$text, $block];} copyright(c) 2012 kuwata-lab.com all rights reserved.
  • Solution: _count_specs() https://gist.github.com/3798000sub _count_specs { my ($nodes) = @_; my $n = 0; for (@$nodes) { if (ref($_) eq HASH) { # topic $n += _count_specs($_->{children}); } elsif (ref($_) eq ARRAY) { # spec $n += 1; } } return $n;} copyright(c) 2012 kuwata-lab.com all rights reserved.
  • Solution: run_all() https://gist.github.com/3798000sub run_all { print "1..", _count_specs($NODES), "n"; _run_all($NODES, 0, 0);}sub _run_all { my ($nodes, $depth, $num) = @_; my $indent = x $depth; for my $x (@$nodes) { if (ref($x) eq HASH) { # topic print "# $indent$x->{prefix} $x->{name}n"; $num = _run_all($x->{children}, $depth + 1, $num); } elsif (ref($x) eq ARRAY) { # spec my ($text, $block) = @$x; $num++; _run_spec($text, $num, $block); } } return $num;} copyright(c) 2012 kuwata-lab.com all rights reserved.
  • Conclustion in this seciton✦ Dont count tests manually. Use computer. テスト数を手動で数えるのはやめてコンピュータにさせよう✦ Noneed to expand TAP specification. Both done_testing() and subtest() are wrong. TAPの仕様拡張は不必要。done_testing()もsubtest()も間違い✦ Intermediate data structure solves the problem. テストを表す中間データ構造を作れば万事解決 copyright(c) 2012 kuwata-lab.com all rights reserved.
  • Section 4:No fixture featureフィクスチャ機能がない copyright(c) 2012 kuwata-lab.com all rights reserved.
  • What is fixture?"A test fixture (also known as a test context) is theset of preconditions or state needed to run a test.The developer should set up a known good statebefore the tests, and return to the original stateafter the tests." http://en.wikipedia.org/wiki/XUnit"テストを実行、成功させるために必要な状態や前提条件の集合を、フィクスチャと呼ぶ。これらはテストコンテキストとも呼ばれる。開発者はテストの実行前にテストに適した状態を整え、テスト実行後に元の状態を復元することが望ましい。" http://ja.wikipedia.org/wiki/XUnit copyright(c) 2012 kuwata-lab.com all rights reserved.
  • Fixture method✦ xUnit • setUp() / tearDown()✦ RSpec • before() / after()✦ Test::More • (nothing!) copyright(c) 2012 kuwata-lab.com all rights reserved.
  • Fault of setUp/tearDownAll tests in a class must share a setUp/tearDown. sub setUp { my ($self) = @_; $self->man = User->new(gender=>M); $self->woman = User->new(gender=>W); } sub test1 { my ($self) = @_; my $user = $self->man; ... } sub test2 { my ($self) = @_; my $user = $self->woman; ... } copyright(c) 2012 kuwata-lab.com all rights reserved.
  • Fault of setUp/tearDownSeparate TestCase class?package FooTestCase;sub setUp { ... }sub testFoo { ... }package BarTestCase;sub setUp { ... }sub testBar { ... } No. Test structure should follow specification reason, not fixture reason. copyright(c) 2012 kuwata-lab.com all rights reserved.
  • Another approach on fixtureDefine fixture method for each test data.sub fx_man { return User->new(gender=>M); }sub fx_woman { return User->new(gender=>W); }spec "test for man", sub { OK(fx_man()->{gender} eq M); }spec "test for woman", sub { OK(fx_woman()->{gender} eq W); } More flexible than setUp/tearDown copyright(c) 2012 kuwata-lab.com all rights reserved.
  • Cons of the approachspec "returns length of file", sub { my $file = fx_file("homhom"); OK(file_length($file) == 6); unlink($file);}; Troublesome task to do teardown for each fixture data fixtureごとに忘れずに解放処理を行うのは面倒 copyright(c) 2012 kuwata-lab.com all rights reserved.
  • Solution: at_end()sub fx_file { my ($content) = (@_); $file = "test-".rand().".txt"; write_file($file, $content); at_end { unlink($file); }; return $file;} Register task called at end of test テストの終わりに実行される処理を登録する copyright(c) 2012 kuwata-lab.com all rights reserved.
  • Solution: at_end()spec "returns length of file", sub { my $file = fx_file("homhom"); OK(file_length($file) == 6); unlink $file;}; No need to teardown for each test テストごとの終了処理を書く必要がなくなる copyright(c) 2012 kuwata-lab.com all rights reserved.
  • Solution: at_end() https://gist.github.com/3798046our @_CLOSURES = ();sub at_end(&) { my ($closure) = @_; push @_CLOSURES, $closure;} copyright(c) 2012 kuwata-lab.com all rights reserved.
  • Solution: _run_spec() https://gist.github.com/3798046sub _run_spec { my ($text, $num, $closure) = @_; eval { $closure->(); }; my $s = $@ ? "ok" : "not ok"; print "$s $num - $textn"; my $@ = undef; for my $clos (reverse(@_CLOSURES)) { $clos->(); } @_CLOSURES = ();} copyright(c) 2012 kuwata-lab.com all rights reserved.
  • Conclusion in this section✦ No fixture feature in Test::More Test::Moreにはfixture機能がない✦ SetUp()/tearDown() are not so good setUp()/tearDown()も良くはない✦ Use end_at() which registers teardown task in setup 作成時に解放処理を登録できるat_end()が便利 copyright(c) 2012 kuwata-lab.com all rights reserved.
  • Section 5:Hard to distinguish assertionsどれがアサーションなのか分かりにくい copyright(c) 2012 kuwata-lab.com all rights reserved.
  • Assertions in xUnitConsistent naming rule for assertion methods.アサーションメソッドに一貫した命名規則がある Easy to distinguish assertions in test code テストコード中でアサーションを見分けるのが簡単assertTrue()assertEqual()assertMatch()assertSet()... copyright(c) 2012 kuwata-lab.com all rights reserved.
  • Assertions in Test::MoreNo naming rule for assertion functions.アサーションメソッドに一貫した命名規則がない Hard to distinguish assertions in test code テストコード中でアサーションを見分けるのが困難ok()is()like()eq_set()cmp_ok()... copyright(c) 2012 kuwata-lab.com all rights reserved.
  • Solution: AssertionObject class https://gist.github.com/3798075Collect assertion functions in a class.アサーション関数を1つのクラスに集約package AssertionObject;## assertion methodssub num_eq { ... }sub str_eq { ... }sub match { ... }... copyright(c) 2012 kuwata-lab.com all rights reserved.
  • Solution: OK() https://gist.github.com/3798075Change OK() which returns AssertionObject.AssertionObjectインスタンスを返すようにOK()を変更sub OK { my ($actual) = @_; return AssertionObject->new($actual);} Easy to distinguish assertions## usage どれがアサーションかすぐ分かるOK (1+1)->num_eq(2);OK ("a")->str_eq("a");OK ("9")->match(qr/^d+/); copyright(c) 2012 kuwata-lab.com all rights reserved.
  • Solution: Operator overload https://gist.github.com/3798075package AssertionObject;use overload == => &num_eq, eq => &str_eq;package main;OK (1+1) == 2; // same as num_eq()OK ("a") eq "a"; // same as str_eq() Shortcut to assertion methods アサーションメソッドを簡単呼び出し copyright(c) 2012 kuwata-lab.com all rights reserved.
  • ok() vs. OK()ok(2 == 1);not ok 1# Failed test at homhom.t line 4.OK(2) == 1;not ok 1# AssertionFailed at homhom.t line 4.# $actual == $expected: failed# actual: 2# expected: 1 copyright(c) 2012 kuwata-lab.com all rights reserved.
  • is() vs. OK()is() :is("1.0", 1.0); #=> not okOK() : OK ("1.0") eq 1.0; #=> not ok OK ("1.0") == 1.0; #=> ok You can choose eq or ==. 文字列演算子と数値演算子を選べる copyright(c) 2012 kuwata-lab.com all rights reserved.
  • Test::More vs. OK()Test::More OK()ok(1+1 == 2); OK (1+1) == 2;isnt(1+1, 0); OK (1+1) != 0;cmp_ok(1+1, >=, 1); OK (1+1) >= 1; Consistent usage 一貫した使い方 copyright(c) 2012 kuwata-lab.com all rights reserved.
  • Conclusion in this section✦ Noconsistent naming rule of assertion functions in Test::Unit Test::Moreにはアサーション関数に一貫した命名規則がない✦ Hard to distinguish assertions in test テストコード中でどれがアサーションか見分けるのが困難✦ Solution: AssertionObject class and operator overload 解決策:AssertionObjectクラスと演算子オーバーロード copyright(c) 2012 kuwata-lab.com all rights reserved.
  • One More Thing...
  • Oktest.pm - a new style testing library http://search.cpan.org/~kwatch/Oktest/lib/Oktest.pmuse strict;use warnings;no warnings void; # RECOMMENDED!use Oktest;topic "ClassName", sub { topic "method_name()", sub { spec "...detail...", sub { OK (1+1) == 2; OK (a x 3) eq aaa; }; };};Oktest::main() if $0 eq __FILE__;1; copyright(c) 2012 kuwata-lab.com all rights reserved.
  • おしまい