SlideShare a Scribd company logo
YAPC::ASIA 2012




What is wrong
on 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
	 	 end
end




              copyright(c) 2012 kuwata-lab.com all rights reserved.
Sample: unittest (Python)

import	 unittest

class	 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::More
like	 $html,	 qr'<h3>Hello</h3>';


                                Higher-level information
                                            より高水準の情報
##	 RSpec
it	 "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/3797929

sub	 spec	 {
	 	 my	 ($text,	 $block)	 =	 @_;
	 	 $block->();
}

##	 usage
spec	 "page	 contains	 section	 title",	 sub	 {
	 	 ok(render()	 =~	 qr`<h1>Hello</h1>`);
};




               copyright(c) 2012 kuwata-lab.com all rights reserved.
Spec First

Step 1. Write specifications
spec	 "...specification1...";
spec	 "...specification2...";
 	 	 	 #=>	 not	 ok	 1	 -	 ...spec...	 #	 TODO
 	 	 	 #=>	 not	 ok	 2	 -	 ...spec...	 #	 TODO

Step 2. Add assertions according to spec
spec	 "...specification...",	 sub	 {
	 	 assertion1;
	 	 assertion2;
};
                copyright(c) 2012 kuwata-lab.com all rights reserved.
Solution: spec()
                                                  https://gist.github.com/3797939

sub	 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 lines
As is - 'ok' when assertion passed, 'not ok' when
        failed
       アサーションが成功したらok、失敗したらnot ok

ok	 1	 -	 assertion1
not	 ok	 2	 -	 assertion2

To be - 'ok' when spec satisfied, 'not ok' when not
       コードが仕様を満たしたらok、満たさなければnot ok

ok	 1	 -	 specification1
not	 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 : N

As is                    Output lines per assertion
                               アサーションごとに出力行
ok	 1
ok	 2
ok	 3

To be
ok	 1	 -	 returns	 pair	 of	 integer

                              Output lines per spec
                                        仕様ごとに出力行


              copyright(c) 2012 kuwata-lab.com all rights reserved.
Solution: OK()
                                                  https://gist.github.com/3797954

sub	 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/3797954
my	 $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.
Point




Test 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 document



Is your test code available
as spec document?
そのコードは仕様書としてほんとに利用できるの?




           copyright(c) 2012 kuwata-lab.com all rights reserved.
Sample: Test::More

use	 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
	 	 end
end


               copyright(c) 2012 kuwata-lab.com all rights reserved.
Sample: RSpec
                                     Test condition or situation
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
	 	 end
end


                copyright(c) 2012 kuwata-lab.com all rights reserved.
Sample: RSpec

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
	 	 end              Specification
                         仕様
end


                copyright(c) 2012 kuwata-lab.com all rights reserved.
Sample: unittest (Python)

import	 unittest

class	 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/unit'
require	 'foo'

class	 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
	 	 end
end
           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.t
1..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.t
1..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.t
1..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.t
1..2
#	 *	 package	 Foo
#	 	 	 *	 sub	 meth1()
#	 	 	 	 	 -	 when	 arg	 is	 passed
ok	 1	 -	 1+1	 should	 be	 2
ok	 2	 -	 1-1	 should	 be	 0




                copyright(c) 2012 kuwata-lab.com all rights reserved.
Solution: subtest() alternatives
                                                   https://gist.github.com/3797976

my	 $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/3797976

my	 $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::More

use	 Test::More	 tests=>2;

is(1+1,	 2);
is(1-1,	 0);



$	 perl	 homhom.t
1..2
ok	 1
ok	 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.t
ok	 1
ok	 2
1..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..1
ok	 1	 -	 package	 Foo
1..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 structure
As is:
is	 1+1,	 2;                                                           ok	 1
is	 1-1,	 0;                                                           ok	 2
                                                                       1..2

To be:
                                   topic
is	 1+1,	 2;                         topic                             1..2
is	 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: xUnit

class	 FooTest(TestCase):
	 	 def	 test1(self):	 ...
	 	 def	 test2(self):	 ...

##	 build	 intermediate	 data	 structure
suite	 =	 TestSuite()
suite.add(FooTest('test1'))
suite.add(FooTest('test2'))

##	 run	 tests
TestRunner().run(suite)


             copyright(c) 2012 kuwata-lab.com all rights reserved.
Solution: topic() and spec()
                                                   https://gist.github.com/3798000

topic	 '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 tree
run_all();


                copyright(c) 2012 kuwata-lab.com all rights reserved.
Solution: topic()
                                                 https://gist.github.com/3798000

my	 $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/3798000

my	 $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/3798000

sub	 _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/3798000
sub	 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
✦ Don't   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 the
set of preconditions or state needed to run a test.
The developer should set up a known good state
before the tests, and return to the original state
after 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/tearDown
All 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/tearDown
Separate 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 fixture
Define 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 approach

spec	 "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/3798046

our	 @_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/3798046

sub	 _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 xUnit

Consistent 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::More

No 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/3798075
Collect assertion functions in a class.
アサーション関数を1つのクラスに集約

package	 AssertionObject;

##	 assertion	 methods
sub	 num_eq	 {	 ...	 }
sub	 str_eq	 {	 ...	 }
sub	 match	 	 {	 ...	 }
...



              copyright(c) 2012 kuwata-lab.com all rights reserved.
Solution: OK()
                                                  https://gist.github.com/3798075
Change 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/3798075

package	 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	 ok


OK() :
 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.pm

use	 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.
おしまい

More Related Content

What's hot

Beginning PHPUnit
Beginning PHPUnitBeginning PHPUnit
Beginning PHPUnitJace Ju
 
C&cpu
C&cpuC&cpu
C&cpu
feathertw
 
C ISRO Debugging
C ISRO DebuggingC ISRO Debugging
C ISRO Debuggingsplix757
 
ITT 2014 - Eric Lafortune - ProGuard, Optimizer and Obfuscator in the Android...
ITT 2014 - Eric Lafortune - ProGuard, Optimizer and Obfuscator in the Android...ITT 2014 - Eric Lafortune - ProGuard, Optimizer and Obfuscator in the Android...
ITT 2014 - Eric Lafortune - ProGuard, Optimizer and Obfuscator in the Android...
Istanbul Tech Talks
 
The Anatomy of an Exploit (NDC TechTown 2019)
The Anatomy of an Exploit (NDC TechTown 2019)The Anatomy of an Exploit (NDC TechTown 2019)
The Anatomy of an Exploit (NDC TechTown 2019)
Patricia Aas
 
Eric Lafortune - ProGuard: Optimizer and obfuscator in the Android SDK
Eric Lafortune - ProGuard: Optimizer and obfuscator in the Android SDKEric Lafortune - ProGuard: Optimizer and obfuscator in the Android SDK
Eric Lafortune - ProGuard: Optimizer and obfuscator in the Android SDK
GuardSquare
 
Eric Lafortune - ProGuard and DexGuard for optimization and protection
Eric Lafortune - ProGuard and DexGuard for optimization and protectionEric Lafortune - ProGuard and DexGuard for optimization and protection
Eric Lafortune - ProGuard and DexGuard for optimization and protection
GuardSquare
 
report
reportreport
Test-driven Development for TYPO3
Test-driven Development for TYPO3Test-driven Development for TYPO3
Test-driven Development for TYPO3Oliver Klee
 
Architecture for Massively Parallel HDL Simulations
Architecture for Massively Parallel HDL Simulations Architecture for Massively Parallel HDL Simulations
Architecture for Massively Parallel HDL Simulations DVClub
 
Eric Lafortune - The Jack and Jill build system
Eric Lafortune - The Jack and Jill build systemEric Lafortune - The Jack and Jill build system
Eric Lafortune - The Jack and Jill build system
GuardSquare
 
12. stl örnekler
12.  stl örnekler12.  stl örnekler
12. stl örnekler
karmuhtam
 
C++ for Java Developers (JavaZone Academy 2018)
C++ for Java Developers (JavaZone Academy 2018)C++ for Java Developers (JavaZone Academy 2018)
C++ for Java Developers (JavaZone Academy 2018)
Patricia Aas
 
The Ring programming language version 1.5.3 book - Part 14 of 184
The Ring programming language version 1.5.3 book - Part 14 of 184The Ring programming language version 1.5.3 book - Part 14 of 184
The Ring programming language version 1.5.3 book - Part 14 of 184
Mahmoud Samir Fayed
 
Test-driven JavaScript Development - OPITZ CONSULTING - Tobias Bosch - Stefa...
Test-driven JavaScript Development - OPITZ CONSULTING -  Tobias Bosch - Stefa...Test-driven JavaScript Development - OPITZ CONSULTING -  Tobias Bosch - Stefa...
Test-driven JavaScript Development - OPITZ CONSULTING - Tobias Bosch - Stefa...
OPITZ CONSULTING Deutschland
 
20130530-PEGjs
20130530-PEGjs20130530-PEGjs
20130530-PEGjszuqqhi 2
 
JBoss Drools
JBoss DroolsJBoss Drools
JBoss DroolsVictor_Cr
 
Make Testing Groovy
Make Testing GroovyMake Testing Groovy
Make Testing Groovy
Paul King
 
Test-Driven Development for TYPO3
Test-Driven Development for TYPO3Test-Driven Development for TYPO3
Test-Driven Development for TYPO3Oliver Klee
 
Phpをいじり倒す10の方法
Phpをいじり倒す10の方法Phpをいじり倒す10の方法
Phpをいじり倒す10の方法Moriyoshi Koizumi
 

What's hot (20)

Beginning PHPUnit
Beginning PHPUnitBeginning PHPUnit
Beginning PHPUnit
 
C&cpu
C&cpuC&cpu
C&cpu
 
C ISRO Debugging
C ISRO DebuggingC ISRO Debugging
C ISRO Debugging
 
ITT 2014 - Eric Lafortune - ProGuard, Optimizer and Obfuscator in the Android...
ITT 2014 - Eric Lafortune - ProGuard, Optimizer and Obfuscator in the Android...ITT 2014 - Eric Lafortune - ProGuard, Optimizer and Obfuscator in the Android...
ITT 2014 - Eric Lafortune - ProGuard, Optimizer and Obfuscator in the Android...
 
The Anatomy of an Exploit (NDC TechTown 2019)
The Anatomy of an Exploit (NDC TechTown 2019)The Anatomy of an Exploit (NDC TechTown 2019)
The Anatomy of an Exploit (NDC TechTown 2019)
 
Eric Lafortune - ProGuard: Optimizer and obfuscator in the Android SDK
Eric Lafortune - ProGuard: Optimizer and obfuscator in the Android SDKEric Lafortune - ProGuard: Optimizer and obfuscator in the Android SDK
Eric Lafortune - ProGuard: Optimizer and obfuscator in the Android SDK
 
Eric Lafortune - ProGuard and DexGuard for optimization and protection
Eric Lafortune - ProGuard and DexGuard for optimization and protectionEric Lafortune - ProGuard and DexGuard for optimization and protection
Eric Lafortune - ProGuard and DexGuard for optimization and protection
 
report
reportreport
report
 
Test-driven Development for TYPO3
Test-driven Development for TYPO3Test-driven Development for TYPO3
Test-driven Development for TYPO3
 
Architecture for Massively Parallel HDL Simulations
Architecture for Massively Parallel HDL Simulations Architecture for Massively Parallel HDL Simulations
Architecture for Massively Parallel HDL Simulations
 
Eric Lafortune - The Jack and Jill build system
Eric Lafortune - The Jack and Jill build systemEric Lafortune - The Jack and Jill build system
Eric Lafortune - The Jack and Jill build system
 
12. stl örnekler
12.  stl örnekler12.  stl örnekler
12. stl örnekler
 
C++ for Java Developers (JavaZone Academy 2018)
C++ for Java Developers (JavaZone Academy 2018)C++ for Java Developers (JavaZone Academy 2018)
C++ for Java Developers (JavaZone Academy 2018)
 
The Ring programming language version 1.5.3 book - Part 14 of 184
The Ring programming language version 1.5.3 book - Part 14 of 184The Ring programming language version 1.5.3 book - Part 14 of 184
The Ring programming language version 1.5.3 book - Part 14 of 184
 
Test-driven JavaScript Development - OPITZ CONSULTING - Tobias Bosch - Stefa...
Test-driven JavaScript Development - OPITZ CONSULTING -  Tobias Bosch - Stefa...Test-driven JavaScript Development - OPITZ CONSULTING -  Tobias Bosch - Stefa...
Test-driven JavaScript Development - OPITZ CONSULTING - Tobias Bosch - Stefa...
 
20130530-PEGjs
20130530-PEGjs20130530-PEGjs
20130530-PEGjs
 
JBoss Drools
JBoss DroolsJBoss Drools
JBoss Drools
 
Make Testing Groovy
Make Testing GroovyMake Testing Groovy
Make Testing Groovy
 
Test-Driven Development for TYPO3
Test-Driven Development for TYPO3Test-Driven Development for TYPO3
Test-Driven Development for TYPO3
 
Phpをいじり倒す10の方法
Phpをいじり倒す10の方法Phpをいじり倒す10の方法
Phpをいじり倒す10の方法
 

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

Advanced Perl Techniques
Advanced Perl TechniquesAdvanced Perl Techniques
Advanced Perl Techniques
Dave Cross
 
Testing Code and Assuring Quality
Testing Code and Assuring QualityTesting Code and Assuring Quality
Testing Code and Assuring Quality
Kent Cowgill
 
Intro to Testing in Zope, Plone
Intro to Testing in Zope, PloneIntro to Testing in Zope, Plone
Intro to Testing in Zope, Plone
Quintagroup
 
using python module: doctest
using python module: doctestusing python module: doctest
using python module: doctest
mitnk
 
Test driven development_for_php
Test driven development_for_phpTest driven development_for_php
Test driven development_for_php
Lean Teams Consultancy
 
Practical Testing of Ruby Core
Practical Testing of Ruby CorePractical Testing of Ruby Core
Practical Testing of Ruby Core
Hiroshi SHIBATA
 
Cより速いRubyプログラム
Cより速いRubyプログラムCより速いRubyプログラム
Cより速いRubyプログラム
kwatch
 
Introducing PHP Latest Updates
Introducing PHP Latest UpdatesIntroducing PHP Latest Updates
Introducing PHP Latest UpdatesIftekhar Eather
 
Groovy Introduction - JAX Germany - 2008
Groovy Introduction - JAX Germany - 2008Groovy Introduction - JAX Germany - 2008
Groovy Introduction - JAX Germany - 2008
Guillaume Laforge
 
Go 1.10 Release Party - PDX Go
Go 1.10 Release Party - PDX GoGo 1.10 Release Party - PDX Go
Go 1.10 Release Party - PDX Go
Rodolfo Carvalho
 
A Lifecycle Of Code Under Test by Robert Fornal
A Lifecycle Of Code Under Test by Robert FornalA Lifecycle Of Code Under Test by Robert Fornal
A Lifecycle Of Code Under Test by Robert Fornal
QA or the Highway
 
Specs2
Specs2Specs2
Spock: Test Well and Prosper
Spock: Test Well and ProsperSpock: Test Well and Prosper
Spock: Test Well and Prosper
Ken Kousen
 
Why you should be using the shiny new C# 6.0 features now!
Why you should be using the shiny new C# 6.0 features now!Why you should be using the shiny new C# 6.0 features now!
Why you should be using the shiny new C# 6.0 features now!
Eric Phan
 
PHPunit and you
PHPunit and youPHPunit and you
PHPunit and you
markstory
 
PHPSpec BDD for PHP
PHPSpec BDD for PHPPHPSpec BDD for PHP
PHPSpec BDD for PHP
Marcello Duarte
 
The $path to knowledge: What little it take to unit-test Perl.
The $path to knowledge: What little it take to unit-test Perl.The $path to knowledge: What little it take to unit-test Perl.
The $path to knowledge: What little it take to unit-test Perl.
Workhorse Computing
 
O CPAN tem as ferramentas que você precisa para fazer TDD em Perl, o Coding D...
O CPAN tem as ferramentas que você precisa para fazer TDD em Perl, o Coding D...O CPAN tem as ferramentas que você precisa para fazer TDD em Perl, o Coding D...
O CPAN tem as ferramentas que você precisa para fazer TDD em Perl, o Coding D...
Rodolfo Carvalho
 
Unit testing in iOS featuring OCUnit, GHUnit & OCMock
Unit testing in iOS featuring OCUnit, GHUnit & OCMockUnit testing in iOS featuring OCUnit, GHUnit & OCMock
Unit testing in iOS featuring OCUnit, GHUnit & OCMockRobot Media
 

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

Advanced Perl Techniques
Advanced Perl TechniquesAdvanced Perl Techniques
Advanced Perl Techniques
 
Testing Code and Assuring Quality
Testing Code and Assuring QualityTesting Code and Assuring Quality
Testing Code and Assuring Quality
 
Intro to Testing in Zope, Plone
Intro to Testing in Zope, PloneIntro to Testing in Zope, Plone
Intro to Testing in Zope, Plone
 
using python module: doctest
using python module: doctestusing python module: doctest
using python module: doctest
 
Test driven development_for_php
Test driven development_for_phpTest driven development_for_php
Test driven development_for_php
 
Practical Testing of Ruby Core
Practical Testing of Ruby CorePractical Testing of Ruby Core
Practical Testing of Ruby Core
 
Cより速いRubyプログラム
Cより速いRubyプログラムCより速いRubyプログラム
Cより速いRubyプログラム
 
Introducing PHP Latest Updates
Introducing PHP Latest UpdatesIntroducing PHP Latest Updates
Introducing PHP Latest Updates
 
Groovy Introduction - JAX Germany - 2008
Groovy Introduction - JAX Germany - 2008Groovy Introduction - JAX Germany - 2008
Groovy Introduction - JAX Germany - 2008
 
Go 1.10 Release Party - PDX Go
Go 1.10 Release Party - PDX GoGo 1.10 Release Party - PDX Go
Go 1.10 Release Party - PDX Go
 
A Lifecycle Of Code Under Test by Robert Fornal
A Lifecycle Of Code Under Test by Robert FornalA Lifecycle Of Code Under Test by Robert Fornal
A Lifecycle Of Code Under Test by Robert Fornal
 
Specs2
Specs2Specs2
Specs2
 
Spock: Test Well and Prosper
Spock: Test Well and ProsperSpock: Test Well and Prosper
Spock: Test Well and Prosper
 
Why you should be using the shiny new C# 6.0 features now!
Why you should be using the shiny new C# 6.0 features now!Why you should be using the shiny new C# 6.0 features now!
Why you should be using the shiny new C# 6.0 features now!
 
PHPunit and you
PHPunit and youPHPunit and you
PHPunit and you
 
PHPSpec BDD for PHP
PHPSpec BDD for PHPPHPSpec BDD for PHP
PHPSpec BDD for PHP
 
The $path to knowledge: What little it take to unit-test Perl.
The $path to knowledge: What little it take to unit-test Perl.The $path to knowledge: What little it take to unit-test Perl.
The $path to knowledge: What little it take to unit-test Perl.
 
O CPAN tem as ferramentas que você precisa para fazer TDD em Perl, o Coding D...
O CPAN tem as ferramentas que você precisa para fazer TDD em Perl, o Coding D...O CPAN tem as ferramentas que você precisa para fazer TDD em Perl, o Coding D...
O CPAN tem as ferramentas que você precisa para fazer TDD em Perl, o Coding D...
 
Unit testing in iOS featuring OCUnit, GHUnit & OCMock
Unit testing in iOS featuring OCUnit, GHUnit & OCMockUnit testing in iOS featuring OCUnit, GHUnit & OCMock
Unit testing in iOS featuring OCUnit, GHUnit & OCMock
 
Hidden Gems of Ruby 1.9
Hidden Gems of Ruby 1.9Hidden Gems of Ruby 1.9
Hidden Gems of Ruby 1.9
 

More from kwatch

How to make the fastest Router in Python
How to make the fastest Router in PythonHow to make the fastest Router in Python
How to make the fastest Router in Python
kwatch
 
Migr8.rb チュートリアル
Migr8.rb チュートリアルMigr8.rb チュートリアル
Migr8.rb チュートリアル
kwatch
 
なんでもID
なんでもIDなんでもID
なんでもID
kwatch
 
Nippondanji氏に怒られても仕方ない、配列型とJSON型の使い方
Nippondanji氏に怒られても仕方ない、配列型とJSON型の使い方Nippondanji氏に怒られても仕方ない、配列型とJSON型の使い方
Nippondanji氏に怒られても仕方ない、配列型とJSON型の使い方
kwatch
 
【SQLインジェクション対策】徳丸先生に怒られない、動的SQLの安全な組み立て方
【SQLインジェクション対策】徳丸先生に怒られない、動的SQLの安全な組み立て方【SQLインジェクション対策】徳丸先生に怒られない、動的SQLの安全な組み立て方
【SQLインジェクション対策】徳丸先生に怒られない、動的SQLの安全な組み立て方
kwatch
 
O/Rマッパーによるトラブルを未然に防ぐ
O/Rマッパーによるトラブルを未然に防ぐO/Rマッパーによるトラブルを未然に防ぐ
O/Rマッパーによるトラブルを未然に防ぐ
kwatch
 
正規表現リテラルは本当に必要なのか?
正規表現リテラルは本当に必要なのか?正規表現リテラルは本当に必要なのか?
正規表現リテラルは本当に必要なのか?
kwatch
 
【公開終了】Python4PHPer - PHPユーザのためのPython入門 (Python2.5)
【公開終了】Python4PHPer - PHPユーザのためのPython入門 (Python2.5)【公開終了】Python4PHPer - PHPユーザのためのPython入門 (Python2.5)
【公開終了】Python4PHPer - PHPユーザのためのPython入門 (Python2.5)
kwatch
 
DBスキーマもバージョン管理したい!
DBスキーマもバージョン管理したい!DBスキーマもバージョン管理したい!
DBスキーマもバージョン管理したい!
kwatch
 
PHPとJavaScriptにおけるオブジェクト指向を比較する
PHPとJavaScriptにおけるオブジェクト指向を比較するPHPとJavaScriptにおけるオブジェクト指向を比較する
PHPとJavaScriptにおけるオブジェクト指向を比較する
kwatch
 
SQL上級者こそ知って欲しい、なぜO/Rマッパーが重要か?
SQL上級者こそ知って欲しい、なぜO/Rマッパーが重要か?SQL上級者こそ知って欲しい、なぜO/Rマッパーが重要か?
SQL上級者こそ知って欲しい、なぜO/Rマッパーが重要か?
kwatch
 
Fantastic DSL in Python
Fantastic DSL in PythonFantastic DSL in Python
Fantastic DSL in Python
kwatch
 
PHP5.5新機能「ジェネレータ」初心者入門
PHP5.5新機能「ジェネレータ」初心者入門PHP5.5新機能「ジェネレータ」初心者入門
PHP5.5新機能「ジェネレータ」初心者入門
kwatch
 
Pretty Good Branch Strategy for Git/Mercurial
Pretty Good Branch Strategy for Git/MercurialPretty Good Branch Strategy for Git/Mercurial
Pretty Good Branch Strategy for Git/Mercurial
kwatch
 
Oktest - a new style testing library for Python -
Oktest - a new style testing library for Python -Oktest - a new style testing library for Python -
Oktest - a new style testing library for Python -
kwatch
 
文字列結合のベンチマークをいろんな処理系でやってみた
文字列結合のベンチマークをいろんな処理系でやってみた文字列結合のベンチマークをいろんな処理系でやってみた
文字列結合のベンチマークをいろんな処理系でやってみた
kwatch
 
I have something to say about the buzz word "From Java to Ruby"
I have something to say about the buzz word "From Java to Ruby"I have something to say about the buzz word "From Java to Ruby"
I have something to say about the buzz word "From Java to Ruby"kwatch
 
Javaより速いLL用テンプレートエンジン
Javaより速いLL用テンプレートエンジンJavaより速いLL用テンプレートエンジン
Javaより速いLL用テンプレートエンジン
kwatch
 
Underlaying Technology of Modern O/R Mapper
Underlaying Technology of Modern O/R MapperUnderlaying Technology of Modern O/R Mapper
Underlaying Technology of Modern O/R Mapper
kwatch
 
How to Make Ruby CGI Script Faster - CGIを高速化する小手先テクニック -
How to Make Ruby CGI Script Faster - CGIを高速化する小手先テクニック -How to Make Ruby CGI Script Faster - CGIを高速化する小手先テクニック -
How to Make Ruby CGI Script Faster - CGIを高速化する小手先テクニック -kwatch
 

More from kwatch (20)

How to make the fastest Router in Python
How to make the fastest Router in PythonHow to make the fastest Router in Python
How to make the fastest Router in Python
 
Migr8.rb チュートリアル
Migr8.rb チュートリアルMigr8.rb チュートリアル
Migr8.rb チュートリアル
 
なんでもID
なんでもIDなんでもID
なんでもID
 
Nippondanji氏に怒られても仕方ない、配列型とJSON型の使い方
Nippondanji氏に怒られても仕方ない、配列型とJSON型の使い方Nippondanji氏に怒られても仕方ない、配列型とJSON型の使い方
Nippondanji氏に怒られても仕方ない、配列型とJSON型の使い方
 
【SQLインジェクション対策】徳丸先生に怒られない、動的SQLの安全な組み立て方
【SQLインジェクション対策】徳丸先生に怒られない、動的SQLの安全な組み立て方【SQLインジェクション対策】徳丸先生に怒られない、動的SQLの安全な組み立て方
【SQLインジェクション対策】徳丸先生に怒られない、動的SQLの安全な組み立て方
 
O/Rマッパーによるトラブルを未然に防ぐ
O/Rマッパーによるトラブルを未然に防ぐO/Rマッパーによるトラブルを未然に防ぐ
O/Rマッパーによるトラブルを未然に防ぐ
 
正規表現リテラルは本当に必要なのか?
正規表現リテラルは本当に必要なのか?正規表現リテラルは本当に必要なのか?
正規表現リテラルは本当に必要なのか?
 
【公開終了】Python4PHPer - PHPユーザのためのPython入門 (Python2.5)
【公開終了】Python4PHPer - PHPユーザのためのPython入門 (Python2.5)【公開終了】Python4PHPer - PHPユーザのためのPython入門 (Python2.5)
【公開終了】Python4PHPer - PHPユーザのためのPython入門 (Python2.5)
 
DBスキーマもバージョン管理したい!
DBスキーマもバージョン管理したい!DBスキーマもバージョン管理したい!
DBスキーマもバージョン管理したい!
 
PHPとJavaScriptにおけるオブジェクト指向を比較する
PHPとJavaScriptにおけるオブジェクト指向を比較するPHPとJavaScriptにおけるオブジェクト指向を比較する
PHPとJavaScriptにおけるオブジェクト指向を比較する
 
SQL上級者こそ知って欲しい、なぜO/Rマッパーが重要か?
SQL上級者こそ知って欲しい、なぜO/Rマッパーが重要か?SQL上級者こそ知って欲しい、なぜO/Rマッパーが重要か?
SQL上級者こそ知って欲しい、なぜO/Rマッパーが重要か?
 
Fantastic DSL in Python
Fantastic DSL in PythonFantastic DSL in Python
Fantastic DSL in Python
 
PHP5.5新機能「ジェネレータ」初心者入門
PHP5.5新機能「ジェネレータ」初心者入門PHP5.5新機能「ジェネレータ」初心者入門
PHP5.5新機能「ジェネレータ」初心者入門
 
Pretty Good Branch Strategy for Git/Mercurial
Pretty Good Branch Strategy for Git/MercurialPretty Good Branch Strategy for Git/Mercurial
Pretty Good Branch Strategy for Git/Mercurial
 
Oktest - a new style testing library for Python -
Oktest - a new style testing library for Python -Oktest - a new style testing library for Python -
Oktest - a new style testing library for Python -
 
文字列結合のベンチマークをいろんな処理系でやってみた
文字列結合のベンチマークをいろんな処理系でやってみた文字列結合のベンチマークをいろんな処理系でやってみた
文字列結合のベンチマークをいろんな処理系でやってみた
 
I have something to say about the buzz word "From Java to Ruby"
I have something to say about the buzz word "From Java to Ruby"I have something to say about the buzz word "From Java to Ruby"
I have something to say about the buzz word "From Java to Ruby"
 
Javaより速いLL用テンプレートエンジン
Javaより速いLL用テンプレートエンジンJavaより速いLL用テンプレートエンジン
Javaより速いLL用テンプレートエンジン
 
Underlaying Technology of Modern O/R Mapper
Underlaying Technology of Modern O/R MapperUnderlaying Technology of Modern O/R Mapper
Underlaying Technology of Modern O/R Mapper
 
How to Make Ruby CGI Script Faster - CGIを高速化する小手先テクニック -
How to Make Ruby CGI Script Faster - CGIを高速化する小手先テクニック -How to Make Ruby CGI Script Faster - CGIを高速化する小手先テクニック -
How to Make Ruby CGI Script Faster - CGIを高速化する小手先テクニック -
 

Recently uploaded

UiPath Test Automation using UiPath Test Suite series, part 3
UiPath Test Automation using UiPath Test Suite series, part 3UiPath Test Automation using UiPath Test Suite series, part 3
UiPath Test Automation using UiPath Test Suite series, part 3
DianaGray10
 
FIDO Alliance Osaka Seminar: FIDO Security Aspects.pdf
FIDO Alliance Osaka Seminar: FIDO Security Aspects.pdfFIDO Alliance Osaka Seminar: FIDO Security Aspects.pdf
FIDO Alliance Osaka Seminar: FIDO Security Aspects.pdf
FIDO Alliance
 
JMeter webinar - integration with InfluxDB and Grafana
JMeter webinar - integration with InfluxDB and GrafanaJMeter webinar - integration with InfluxDB and Grafana
JMeter webinar - integration with InfluxDB and Grafana
RTTS
 
Accelerate your Kubernetes clusters with Varnish Caching
Accelerate your Kubernetes clusters with Varnish CachingAccelerate your Kubernetes clusters with Varnish Caching
Accelerate your Kubernetes clusters with Varnish Caching
Thijs Feryn
 
Assuring Contact Center Experiences for Your Customers With ThousandEyes
Assuring Contact Center Experiences for Your Customers With ThousandEyesAssuring Contact Center Experiences for Your Customers With ThousandEyes
Assuring Contact Center Experiences for Your Customers With ThousandEyes
ThousandEyes
 
Bits & Pixels using AI for Good.........
Bits & Pixels using AI for Good.........Bits & Pixels using AI for Good.........
Bits & Pixels using AI for Good.........
Alison B. Lowndes
 
De-mystifying Zero to One: Design Informed Techniques for Greenfield Innovati...
De-mystifying Zero to One: Design Informed Techniques for Greenfield Innovati...De-mystifying Zero to One: Design Informed Techniques for Greenfield Innovati...
De-mystifying Zero to One: Design Informed Techniques for Greenfield Innovati...
Product School
 
Encryption in Microsoft 365 - ExpertsLive Netherlands 2024
Encryption in Microsoft 365 - ExpertsLive Netherlands 2024Encryption in Microsoft 365 - ExpertsLive Netherlands 2024
Encryption in Microsoft 365 - ExpertsLive Netherlands 2024
Albert Hoitingh
 
AI for Every Business: Unlocking Your Product's Universal Potential by VP of ...
AI for Every Business: Unlocking Your Product's Universal Potential by VP of ...AI for Every Business: Unlocking Your Product's Universal Potential by VP of ...
AI for Every Business: Unlocking Your Product's Universal Potential by VP of ...
Product School
 
FIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdf
FIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdfFIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdf
FIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdf
FIDO Alliance
 
Empowering NextGen Mobility via Large Action Model Infrastructure (LAMI): pav...
Empowering NextGen Mobility via Large Action Model Infrastructure (LAMI): pav...Empowering NextGen Mobility via Large Action Model Infrastructure (LAMI): pav...
Empowering NextGen Mobility via Large Action Model Infrastructure (LAMI): pav...
Thierry Lestable
 
State of ICS and IoT Cyber Threat Landscape Report 2024 preview
State of ICS and IoT Cyber Threat Landscape Report 2024 previewState of ICS and IoT Cyber Threat Landscape Report 2024 preview
State of ICS and IoT Cyber Threat Landscape Report 2024 preview
Prayukth K V
 
Slack (or Teams) Automation for Bonterra Impact Management (fka Social Soluti...
Slack (or Teams) Automation for Bonterra Impact Management (fka Social Soluti...Slack (or Teams) Automation for Bonterra Impact Management (fka Social Soluti...
Slack (or Teams) Automation for Bonterra Impact Management (fka Social Soluti...
Jeffrey Haguewood
 
From Siloed Products to Connected Ecosystem: Building a Sustainable and Scala...
From Siloed Products to Connected Ecosystem: Building a Sustainable and Scala...From Siloed Products to Connected Ecosystem: Building a Sustainable and Scala...
From Siloed Products to Connected Ecosystem: Building a Sustainable and Scala...
Product School
 
Smart TV Buyer Insights Survey 2024 by 91mobiles.pdf
Smart TV Buyer Insights Survey 2024 by 91mobiles.pdfSmart TV Buyer Insights Survey 2024 by 91mobiles.pdf
Smart TV Buyer Insights Survey 2024 by 91mobiles.pdf
91mobiles
 
Unsubscribed: Combat Subscription Fatigue With a Membership Mentality by Head...
Unsubscribed: Combat Subscription Fatigue With a Membership Mentality by Head...Unsubscribed: Combat Subscription Fatigue With a Membership Mentality by Head...
Unsubscribed: Combat Subscription Fatigue With a Membership Mentality by Head...
Product School
 
DevOps and Testing slides at DASA Connect
DevOps and Testing slides at DASA ConnectDevOps and Testing slides at DASA Connect
DevOps and Testing slides at DASA Connect
Kari Kakkonen
 
Mission to Decommission: Importance of Decommissioning Products to Increase E...
Mission to Decommission: Importance of Decommissioning Products to Increase E...Mission to Decommission: Importance of Decommissioning Products to Increase E...
Mission to Decommission: Importance of Decommissioning Products to Increase E...
Product School
 
From Daily Decisions to Bottom Line: Connecting Product Work to Revenue by VP...
From Daily Decisions to Bottom Line: Connecting Product Work to Revenue by VP...From Daily Decisions to Bottom Line: Connecting Product Work to Revenue by VP...
From Daily Decisions to Bottom Line: Connecting Product Work to Revenue by VP...
Product School
 
GraphRAG is All You need? LLM & Knowledge Graph
GraphRAG is All You need? LLM & Knowledge GraphGraphRAG is All You need? LLM & Knowledge Graph
GraphRAG is All You need? LLM & Knowledge Graph
Guy Korland
 

Recently uploaded (20)

UiPath Test Automation using UiPath Test Suite series, part 3
UiPath Test Automation using UiPath Test Suite series, part 3UiPath Test Automation using UiPath Test Suite series, part 3
UiPath Test Automation using UiPath Test Suite series, part 3
 
FIDO Alliance Osaka Seminar: FIDO Security Aspects.pdf
FIDO Alliance Osaka Seminar: FIDO Security Aspects.pdfFIDO Alliance Osaka Seminar: FIDO Security Aspects.pdf
FIDO Alliance Osaka Seminar: FIDO Security Aspects.pdf
 
JMeter webinar - integration with InfluxDB and Grafana
JMeter webinar - integration with InfluxDB and GrafanaJMeter webinar - integration with InfluxDB and Grafana
JMeter webinar - integration with InfluxDB and Grafana
 
Accelerate your Kubernetes clusters with Varnish Caching
Accelerate your Kubernetes clusters with Varnish CachingAccelerate your Kubernetes clusters with Varnish Caching
Accelerate your Kubernetes clusters with Varnish Caching
 
Assuring Contact Center Experiences for Your Customers With ThousandEyes
Assuring Contact Center Experiences for Your Customers With ThousandEyesAssuring Contact Center Experiences for Your Customers With ThousandEyes
Assuring Contact Center Experiences for Your Customers With ThousandEyes
 
Bits & Pixels using AI for Good.........
Bits & Pixels using AI for Good.........Bits & Pixels using AI for Good.........
Bits & Pixels using AI for Good.........
 
De-mystifying Zero to One: Design Informed Techniques for Greenfield Innovati...
De-mystifying Zero to One: Design Informed Techniques for Greenfield Innovati...De-mystifying Zero to One: Design Informed Techniques for Greenfield Innovati...
De-mystifying Zero to One: Design Informed Techniques for Greenfield Innovati...
 
Encryption in Microsoft 365 - ExpertsLive Netherlands 2024
Encryption in Microsoft 365 - ExpertsLive Netherlands 2024Encryption in Microsoft 365 - ExpertsLive Netherlands 2024
Encryption in Microsoft 365 - ExpertsLive Netherlands 2024
 
AI for Every Business: Unlocking Your Product's Universal Potential by VP of ...
AI for Every Business: Unlocking Your Product's Universal Potential by VP of ...AI for Every Business: Unlocking Your Product's Universal Potential by VP of ...
AI for Every Business: Unlocking Your Product's Universal Potential by VP of ...
 
FIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdf
FIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdfFIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdf
FIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdf
 
Empowering NextGen Mobility via Large Action Model Infrastructure (LAMI): pav...
Empowering NextGen Mobility via Large Action Model Infrastructure (LAMI): pav...Empowering NextGen Mobility via Large Action Model Infrastructure (LAMI): pav...
Empowering NextGen Mobility via Large Action Model Infrastructure (LAMI): pav...
 
State of ICS and IoT Cyber Threat Landscape Report 2024 preview
State of ICS and IoT Cyber Threat Landscape Report 2024 previewState of ICS and IoT Cyber Threat Landscape Report 2024 preview
State of ICS and IoT Cyber Threat Landscape Report 2024 preview
 
Slack (or Teams) Automation for Bonterra Impact Management (fka Social Soluti...
Slack (or Teams) Automation for Bonterra Impact Management (fka Social Soluti...Slack (or Teams) Automation for Bonterra Impact Management (fka Social Soluti...
Slack (or Teams) Automation for Bonterra Impact Management (fka Social Soluti...
 
From Siloed Products to Connected Ecosystem: Building a Sustainable and Scala...
From Siloed Products to Connected Ecosystem: Building a Sustainable and Scala...From Siloed Products to Connected Ecosystem: Building a Sustainable and Scala...
From Siloed Products to Connected Ecosystem: Building a Sustainable and Scala...
 
Smart TV Buyer Insights Survey 2024 by 91mobiles.pdf
Smart TV Buyer Insights Survey 2024 by 91mobiles.pdfSmart TV Buyer Insights Survey 2024 by 91mobiles.pdf
Smart TV Buyer Insights Survey 2024 by 91mobiles.pdf
 
Unsubscribed: Combat Subscription Fatigue With a Membership Mentality by Head...
Unsubscribed: Combat Subscription Fatigue With a Membership Mentality by Head...Unsubscribed: Combat Subscription Fatigue With a Membership Mentality by Head...
Unsubscribed: Combat Subscription Fatigue With a Membership Mentality by Head...
 
DevOps and Testing slides at DASA Connect
DevOps and Testing slides at DASA ConnectDevOps and Testing slides at DASA Connect
DevOps and Testing slides at DASA Connect
 
Mission to Decommission: Importance of Decommissioning Products to Increase E...
Mission to Decommission: Importance of Decommissioning Products to Increase E...Mission to Decommission: Importance of Decommissioning Products to Increase E...
Mission to Decommission: Importance of Decommissioning Products to Increase E...
 
From Daily Decisions to Bottom Line: Connecting Product Work to Revenue by VP...
From Daily Decisions to Bottom Line: Connecting Product Work to Revenue by VP...From Daily Decisions to Bottom Line: Connecting Product Work to Revenue by VP...
From Daily Decisions to Bottom Line: Connecting Product Work to Revenue by VP...
 
GraphRAG is All You need? LLM & Knowledge Graph
GraphRAG is All You need? LLM & Knowledge GraphGraphRAG is All You need? LLM & Knowledge Graph
GraphRAG is All You need? LLM & Knowledge Graph
 

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

  • 1. YAPC::ASIA 2012 What is wrong on 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.
  • 2. 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.
  • 3. Section 1: Testing without spec 仕様を書かずにテストしている copyright(c) 2012 kuwata-lab.com all rights reserved.
  • 4. Point Write your test according to spec, not your code. テストは、コードではなく仕様をもとに書け。 copyright(c) 2012 kuwata-lab.com all rights reserved.
  • 5. 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.
  • 6. 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 end end copyright(c) 2012 kuwata-lab.com all rights reserved.
  • 7. Sample: unittest (Python) import unittest class 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.
  • 8. 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.
  • 9. Difference between Test::More and RSpec ## Test::More like $html, qr'<h3>Hello</h3>'; Higher-level information より高水準の情報 ## RSpec it "contains section title" do html.should =~ %r'<h3>Hello</h3>' end copyright(c) 2012 kuwata-lab.com all rights reserved.
  • 10. Solution: spec() https://gist.github.com/3797929 sub spec { my ($text, $block) = @_; $block->(); } ## usage spec "page contains section title", sub { ok(render() =~ qr`<h1>Hello</h1>`); }; copyright(c) 2012 kuwata-lab.com all rights reserved.
  • 11. Spec First Step 1. Write specifications spec "...specification1..."; spec "...specification2..."; #=> not ok 1 - ...spec... # TODO #=> not ok 2 - ...spec... # TODO Step 2. Add assertions according to spec spec "...specification...", sub { assertion1; assertion2; }; copyright(c) 2012 kuwata-lab.com all rights reserved.
  • 12. Solution: spec() https://gist.github.com/3797939 sub 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.
  • 13. Meaning of output lines As is - 'ok' when assertion passed, 'not ok' when failed アサーションが成功したらok、失敗したらnot ok ok 1 - assertion1 not ok 2 - assertion2 To be - 'ok' when spec satisfied, 'not ok' when not コードが仕様を満たしたらok、満たさなければnot ok ok 1 - specification1 not ok 2 - specification2 copyright(c) 2012 kuwata-lab.com all rights reserved.
  • 14. 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.
  • 15. Spec : Assertion = 1 : N As is Output lines per assertion アサーションごとに出力行 ok 1 ok 2 ok 3 To be ok 1 - returns pair of integer Output lines per spec 仕様ごとに出力行 copyright(c) 2012 kuwata-lab.com all rights reserved.
  • 16. Solution: OK() https://gist.github.com/3797954 sub 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.
  • 17. Solution: spec() https://gist.github.com/3797954 my $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.
  • 18. 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.
  • 19. Section 2: Not structured tests テストが構造化されてない copyright(c) 2012 kuwata-lab.com all rights reserved.
  • 20. Point Test should have structure. Because spec has structure. テストには構造がある。なぜなら仕様に構造があるから。 copyright(c) 2012 kuwata-lab.com all rights reserved.
  • 21. Sample: Specification document クラス:Calendar メソッド:isLeapYear(int year): boolean 動作詳細: ・100で割り切れる場合、 ・400で割り切れる場合はtrueを返す ・それ以外はfalseを返す ・4で割り切れる場合はtrueを返す ・それ以外はfalseを返す copyright(c) 2012 kuwata-lab.com all rights reserved.
  • 22. Test code as spec document Is your test code available as spec document? そのコードは仕様書としてほんとに利用できるの? copyright(c) 2012 kuwata-lab.com all rights reserved.
  • 23. Sample: Test::More use 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.
  • 24. 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 end end copyright(c) 2012 kuwata-lab.com all rights reserved.
  • 25. Sample: RSpec Test condition or situation 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 end end copyright(c) 2012 kuwata-lab.com all rights reserved.
  • 26. Sample: RSpec 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 end Specification 仕様 end copyright(c) 2012 kuwata-lab.com all rights reserved.
  • 27. Sample: unittest (Python) import unittest class 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.
  • 28. Sample: Test::Unit2 (Ruby) require 'test/unit' require 'foo' class 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 end end ref: http://www.clear-code.com/blog/2012/4/25.html copyright(c) 2012 kuwata-lab.com all rights reserved.
  • 29. 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.
  • 30. Sample: subtest() (Test::More) $ perl homhom.t 1..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.
  • 31. Sample: subtest() (Test::More) $ perl homhom.t 1..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.
  • 32. Sample: subtest() (Test::More) $ perl homhom.t 1..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.
  • 33. 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.
  • 34. Solution: subtest() alternatives $ perl homhom.t 1..2 # * package Foo # * sub meth1() # - when arg is passed ok 1 - 1+1 should be 2 ok 2 - 1-1 should be 0 copyright(c) 2012 kuwata-lab.com all rights reserved.
  • 35. Solution: subtest() alternatives https://gist.github.com/3797976 my $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.
  • 36. Solution: subtest() alternatives https://gist.github.com/3797976 my $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.
  • 37. 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.
  • 38. Section 3: Needs test plan 事前にテストプラン (=テスト数) を必要とする copyright(c) 2012 kuwata-lab.com all rights reserved.
  • 39. Sample: Test::More use Test::More tests=>2; is(1+1, 2); is(1-1, 0); $ perl homhom.t 1..2 ok 1 ok 2 copyright(c) 2012 kuwata-lab.com all rights reserved.
  • 40. 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.
  • 41. 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.
  • 42. 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.
  • 43. Sample: done_testing() use Test::More tests=>2; is(1+1, 2); is(1-1, 0); done_testing(); $ perl homhom.t ok 1 ok 2 1..2 copyright(c) 2012 kuwata-lab.com all rights reserved.
  • 44. 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.
  • 45. Solution: subtest() alternatives $ perl homhom.pl ok 1 ok 2 1..2 ok 1 - sub meth1() 1..1 ok 1 - package Foo 1..1 copyright(c) 2012 kuwata-lab.com all rights reserved.
  • 46. Pros of done_testing() ✦ No need to speicfy test plan! テスト数を指定しなくていい! copyright(c) 2012 kuwata-lab.com all rights reserved.
  • 47. 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.
  • 48. 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.
  • 49. 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.
  • 50. Solution: Intermediate data structure As is: is 1+1, 2; ok 1 is 1-1, 0; ok 2 1..2 To be: topic is 1+1, 2; topic 1..2 is 1-1, 0; ok 1 spec ok 2 spec Easy to count tests copyright(c) 2012 kuwata-lab.com all rights reserved.
  • 51. 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.
  • 52. Sample: xUnit class FooTest(TestCase): def test1(self): ... def test2(self): ... ## build intermediate data structure suite = TestSuite() suite.add(FooTest('test1')) suite.add(FooTest('test2')) ## run tests TestRunner().run(suite) copyright(c) 2012 kuwata-lab.com all rights reserved.
  • 53. Solution: topic() and spec() https://gist.github.com/3798000 topic '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 tree run_all(); copyright(c) 2012 kuwata-lab.com all rights reserved.
  • 54. Solution: topic() https://gist.github.com/3798000 my $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.
  • 55. Solution: spec() https://gist.github.com/3798000 my $NODES = []; sub spec { my ($text, $block) = @_; push @$NODES, [$text, $block]; } copyright(c) 2012 kuwata-lab.com all rights reserved.
  • 56. Solution: _count_specs() https://gist.github.com/3798000 sub _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.
  • 57. Solution: run_all() https://gist.github.com/3798000 sub 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.
  • 58. Conclustion in this seciton ✦ Don't 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.
  • 59. Section 4: No fixture feature フィクスチャ機能がない copyright(c) 2012 kuwata-lab.com all rights reserved.
  • 60. What is fixture? "A test fixture (also known as a test context) is the set of preconditions or state needed to run a test. The developer should set up a known good state before the tests, and return to the original state after the tests." http://en.wikipedia.org/wiki/XUnit "テストを実行、成功させるために必要な状態や前提条件の集合 を、フィクスチャと呼ぶ。これらはテストコンテキストとも呼 ばれる。開発者はテストの実行前にテストに適した状態を整 え、テスト実行後に元の状態を復元することが望ましい。" http://ja.wikipedia.org/wiki/XUnit copyright(c) 2012 kuwata-lab.com all rights reserved.
  • 61. Fixture method ✦ xUnit • setUp() / tearDown() ✦ RSpec • before() / after() ✦ Test::More • (nothing!) copyright(c) 2012 kuwata-lab.com all rights reserved.
  • 62. Fault of setUp/tearDown All 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.
  • 63. Fault of setUp/tearDown Separate 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.
  • 64. Another approach on fixture Define 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.
  • 65. Cons of the approach spec "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.
  • 66. 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.
  • 67. 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.
  • 68. Solution: at_end() https://gist.github.com/3798046 our @_CLOSURES = (); sub at_end(&) { my ($closure) = @_; push @_CLOSURES, $closure; } copyright(c) 2012 kuwata-lab.com all rights reserved.
  • 69. Solution: _run_spec() https://gist.github.com/3798046 sub _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.
  • 70. 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.
  • 71. Section 5: Hard to distinguish assertions どれがアサーションなのか分かりにくい copyright(c) 2012 kuwata-lab.com all rights reserved.
  • 72. Assertions in xUnit Consistent 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.
  • 73. Assertions in Test::More No 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.
  • 74. Solution: AssertionObject class https://gist.github.com/3798075 Collect assertion functions in a class. アサーション関数を1つのクラスに集約 package AssertionObject; ## assertion methods sub num_eq { ... } sub str_eq { ... } sub match { ... } ... copyright(c) 2012 kuwata-lab.com all rights reserved.
  • 75. Solution: OK() https://gist.github.com/3798075 Change 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.
  • 76. Solution: Operator overload https://gist.github.com/3798075 package 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.
  • 77. 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.
  • 78. is() vs. OK() is() : is("1.0", 1.0); #=> not ok OK() : 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.
  • 79. 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.
  • 80. 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.
  • 82. Oktest.pm - a new style testing library http://search.cpan.org/~kwatch/Oktest/lib/Oktest.pm use 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.