あんなテスト、こんなテスト(this and that about testing)
Upcoming SlideShare
Loading in...5
×
 

Like this? Share it with your network

Share

あんなテスト、こんなテスト(this and that about testing)

on

  • 3,751 views

 

Statistics

Views

Total Views
3,751
Views on SlideShare
2,984
Embed Views
767

Actions

Likes
7
Downloads
10
Comments
0

9 Embeds 767

http://d.hatena.ne.jp 590
http://docs.intra.mixi.co.jp 67
http://yapcasia.org 49
http://saisa.hateblo.jp 39
http://paper.li 16
http://a0.twimg.com 3
http://b.hatena.ne.jp 1
http://webcache.googleusercontent.com 1
https://twitter.com 1
More...

Accessibility

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

あんなテスト、こんなテスト(this and that about testing) Presentation Transcript

  • 1. あんなテスト・こんなテスト (This and That about testing) 土田 拓也(Takuya Tsuchida) @tsucchi 2011/10/15 id: tsucchi1022 エレクトロニクス事業本部Public/公開情報 -1-
  • 2. Abstract  テストの話をします (Ill be talking about testing)  とくに「テストしにくい部分をどのようにテストするか」について話し ます (Especially, Ill talk about how to test the part which is hard to test)Public/公開情報 -2-
  • 3. About Me  土田 拓也(Takuya Tsuchida)  所属: 凸版印刷株式会社 エレクトロニクス事業本部 システム開発部 (TOPPAN PRINTING Co., LTD Electronics Division System Development team)  仕事: MES(製造実行システム)の開発・運用など (Develop and operate MES(Manufacturing Execution System)) – DB 設計したり、SQL 書いたり、Perl 書いたりしています (designing DB schema, writing SQL and Perl etc)  CPAN(PAUSE): TSUCCHI  id(hatena): tsucchi1022  twitter: @tsucchi  github: https://github.com/tsucchiPublic/公開情報 -3-
  • 4. testcodes  テストコード、書いてますか? (Do You Write testcodes?)  テストコードとは(What is the testcode?) – 「入力」と「その入力に対して、期待する出力」を書いて、一致するかど うかを検証するプログラム (programs which validates input and expected output from the provided input are correct.)Public/公開情報 -4-
  • 5. Automated Testing (2)  Example) testing add() subroutine #!/usr/bin/perl -w use strict; use warnings; use Test::More; Subroutine to be tested sub add { my (@inputs) = @_; my $result = 0; for my $input ( @inputs ) { $result += $input; } return $result; } Input for test # testing add subroutine Expected output is( add(1, 2), 3 ); is( add( (1 .. 10) ), 55 ); done_testing();Public/公開情報 -5-
  • 6. Strong points and Weak Points  長所(strong points) – 繰り返し実行できる(It enables to run any time) • 改修やリファクタリングでエンバグしていないか容易 に調べられる(You can easily find whether enbug or not when you finished bug-fix or refactorings) • Jenkins などの CI サーバと組み合わせることで、コ ミット時などの任意のタイミングでテストを実施でき る(Combine with CI server, It is enable to run tests any time such as after commit)  短所(weak points) – イニシャルコストが上がる (increase initial costs) – テストを書きにくい場合がある (Sometimes, It is hard to write testcodes)Public/公開情報 -6-
  • 7. When It is hard to write testcode  「入力」や「出力」が明確ではなかったり、作りにくい場合 (Inputs or outputs are ambiguous or hard to make these) – 標準入出力(STDIN/STDOUT) – コマンドラインオプション (commandline options) – 時刻(system clock) – DB – etc.  これらを、「なんとかする」やり方を紹介します (Ill introduce how to deal with such things)Public/公開情報 -7-
  • 8.  標準入出力(STDIN/STDOUT)  コマンドラインオプション (commandline options)  時刻(system clock)  DB  etc.Public/公開情報 -8-
  • 9. Tests for STDIN/STDOUT  Principle – 内部のロジックが良くテストされているなら、無理して実施する必 要は無い(If internal logic is well tested, It is no need to test STDIN/STDOUT forcefully)  Example Situation – コマンドラインツールのテストをしたい(want to test command-line tool) – 外部モジュールの中間出力が見たいが、その内容が標準出力 を使っている(middle output for external modules, but the output is printed in STDOUT/STDERR) – warn/carp の内容を確認したい(want to check output by warn/carp)  Solution – use IO::Scalar – use Capture::Tiny(for STDOUT/STDERR) – use IO::Capture::STDOUT/STDERR – tie STDIN/STDOUT/STDERRPublic/公開情報
  • 10. Automated Testing (2)  Ex 1)using IO::Scalar and capture STDIN #!/usr/bin/perl -w use strict; use warnings; use Test::More; sub add { my $result = 0; while( <STDIN> ) { chomp; $result += $_; } return $result; } subtest add, sub { my $inputs = "1n2n3n"; # input from STDIN open my $stdin_fh, <, $inputs; local *STDIN = *$stdin_fh; # replace default STDIN is( add(), 6 ); }; done_testing();Public/公開情報 - 10 -
  • 11. Automated Testing (2)  Ex 2) using Capture::Tiny(for STDOUT/STDERR) #!/usr/bin/perl -w use strict; use warnings; use Test::More; use Capture::Tiny qw(capture); sub add { my($a, $b) = @_; print $a + $b; } my ($stdout) = capture { add(1, 2); }; is($stdout, 3); done_testing(); – 簡単に使えるので、Test::Warn の代用とするのも良いと思う (I think its good idea to use this module alternate for Test::Warn)Public/公開情報 - 11 -
  • 12.  標準入出力(STDIN/STDOUT)  コマンドラインオプション (commandline options)  時刻(system clock)  DB  etc.Public/公開情報 - 12 -
  • 13. Tests for command-line args  Principle – 内部のロジックが良くテストされているなら、無理して実施する必 要は無い(If internal logic is well tested, It is no need to test STDIN/STDOUT forcefully)  Example Situation – コマンドラインツールのテストをしたい(want to test command-line tool) – GetOpt::* を使わず、自前でオプション解析しているのを直したい (want to fix because it has self-implemented command-line args analysis)  Solution – @ARGV を書き換えるPublic/公開情報
  • 14. Tests for command-line args  Ex) testing command-line args #!/usr/bin/perl -w use strict; use warnings; use Test::More; our $a_str = undef; # 本当は別 package にある / in real case, this subroutine is defined in other package sub read_args { while ( $_ = shift @ARGV ) { if ( $_ =~ /^-a$/ ) { $a_str = shift @ARGV; } # ... other option analyses are follows } } subtest a option with arg test, sub { $a_str = undef; local @ARGV = ("-a", "a_value"); #ここにオプションを指定 / passes options here read_args(); is($a_str, "a_value"); }; done_testing();Public/公開情報 - 14 -
  • 15.  標準入出力(STDIN/STDOUT)  コマンドラインオプション (commandline options)  時刻(system clock)  DB  etc.Public/公開情報 - 15 -
  • 16. Tests for system clock  Principle – 時刻に依存せずテストが書かれるべき(Tests should be written in no depencency to system clock)  Example Situation – ログの日付フォーマットが正しいかチェックしたい(want to test datetime format in logs) – ロット番号など、日付によって処理内容が変わるものをテストした い(want to test what changes depending on datetime such as lot-no)  Solution – 時刻を改竄する(alter perls system clock) • use Test::MockTime • use Time::Mock • CORE::GLOBAL::time() を書き換える(override CORE::GLOBAL::time)Public/公開情報
  • 17. Tests for system clock  Ex) Test::MockTime #!/usr/bin/perl use strict; use warnings; BEGIN { $ENV{TZ} = JST } use Test::MockTime qw(set_fixed_time); use Test::More; use POSIX qw(strftime); sub some_lot_no { return strftime("%Y%m%d-%H%M%S", localtime()); } set_fixed_time(2009-03-23T11:22:33); is( some_lot_no(), 20090323-112233); done_testing();Public/公開情報 - 17 -
  • 18.  標準入出力(STDIN/STDOUT)  コマンドラインオプション (commandline options)  時刻(system clock)  DB  etc.Public/公開情報 - 18 -
  • 19. Tests for DB  Principle – 基本はモック(DBD::Mock)を使うべき(Mock should be used) – ビジネスロジックと DB は切り離すべき(Business logics and DB should be separated)  Example Situation – ストアドプロシージャをテストしたい(want to test stored procedure) – ORM を使わず、生の DBI を使っているので SQL をテストしたい (want to test SQL because we dont use ORM)  Solution – データを流し込む(load data into DB) – Test::mysqld + something • Test::Fixture::DBI • Test::DBUnit • Test::DataLoader::MySQLPublic/公開情報
  • 20.  標準入出力(STDIN/STDOUT)  コマンドラインオプション (commandline options)  時刻(system clock)  DB  etc.Public/公開情報 - 20 -
  • 21. exit measures(1)  テスト中に exit が呼ばれると、意図せずテストが通ってしまう (If exit() is called, tests are passed accidentally)  Example Situation – 他人のコードを引き継いだ際(when takeover someones code) – ライブラリがエラー処理後に exit を呼んでいた(library routine calls exit after error handling)  Solution – exit()の上書き(override exit) – exit を使っている関数/メソッドの上書き(override subroutine/method which uses exit)Public/公開情報 - 21 -
  • 22. Exit measures(2)  Ex1) exit() causes problem #!/usr/bin/perl -w use strict; use warnings; use Test::More no_plan; my $important_value = ; sub evil_operation { $important_value = "aaa"; exit 0; } ok(1); evil_operation(); is( $important_value, ); % prove exit.t exit.t .. ok All tests successful. Files=1, Tests=1, 0 wallclock secs ( 0.04 usr 0.00 sys + 0.01 cusr 0.01 csys = 0.06 CPU) Result: PASS – This test successes unexpectedlyPublic/公開情報 - 22 -
  • 23. Exit measures(3)  Ex2) measured exit() call #!/usr/bin/perl -w use strict; use warnings; use Test::More no_plan; BEGIN { *CORE::GLOBAL::exit = sub { die unexpected exit called! } } # ADD THIS! my $important_value = ; sub evil_operation { $important_value = "aaa"; exit 0; } ok(1); evil_operation(); is( $important_value, ); % prove exit_measured.t exit_measured.t .. 1/? unexpected exit called! at exit_measured.t line 6. ...(snip) Result: FAIL – Its OK. It should be failed.Public/公開情報 - 23 -
  • 24. setUp/tearDown(1)  xUnit を使っていた人は setUp/tearDown が使いたいかも (xUnit users may want to use setup/tearDown) – それ Test::Class で出来るよ! (Test::Class enables it!) #!/usr/bin/perl -w use strict; use warnings; use Test::Class; MyTest->runtests(); package MyTest; use parent qw(Test::Class); use Test::More; sub set_up :Test(setup) { diag("setup"); } sub tear_down :Test(teardown) { diag("teardown"); } sub my_test :Test(1) { ok(1); #this is some test } sub my_test2 :Test(1) { is("1", "1"); #this is another test }Public/公開情報 - 24 -
  • 25. setUp/tearDown(2)  でも書き方が変わるのは面倒くさい (But it isnt good that how to write test is changed) – subtest + Hook::LexWrap #!/usr/bin/perl -w use strict; use warnings; use Test::More; use Hook::LexWrap; wrap subtest, pre => sub { diag("setup"); }, #alternate for setup post => sub { diag("teardown");} #alternate for teardown ; subtest my_test, sub { ok(1); }; subtest my_test2, sub { is("1", "1"); }; done_testing();Public/公開情報 - 25 -
  • 26. setUp/tearDown(3)  実行例(execution example) % perl setup_teardown.t # setup setup called ok 1 1..1 ok 1 - my_test test called # teardown # setup teardown called ok 1 1..1 ok 2 - my_test2 # teardown 1..2Public/公開情報 - 26 -
  • 27. Caution(1)  今回紹介したテクニックをプロダクションコード側で使わない (Dont use these techniques in production code) – プロダクションコードでモンキーパッチしたり、時間や CORE::GLOBAL::* を書き換えたり、@ARGV 書き換えた り、標準入出力捕まえたりしないこと (In production code, dont monkey-patch, dont alter system clock, dont replace CORE::GLOBAL::*, dont replace @ARGV, and dont capture STDIN/STDOUT) – テストでは有効なテクニックでも、プロダクションコードで使 うと妙なバグに振り回されるかもしれません (These techniques are useful in testcode, but you may encounter curious bugs if using it in production code)Public/公開情報 - 27 -
  • 28. Caution(2)  「テストしにくい部分を何とかしたい!」という考えは基本的には何 かが間違っています (I think it is wrong opinion such as I want to manage testcode which is hard to be written) – 段階的に直していくべき(It should be fixed gradually) – Mock 使うとか、他の部分をテストしてカバーするとか (using Mock or tests other parts to cover it)Public/公開情報 - 28 -
  • 29. Conclusion  テストしにくいものも、Perl だと結構なんとかなります (Sometimes it is hard to write testcode, but Perl provides power to make it possible)  「どうやったら、このテストしにくいコードを何とかできるか」を考え るのは結構楽しい (It is fun thinking about how to write testcode which is hard to be written) – とくにレガシーコードを相手にする場合は (especially for legacy codes)  テストを書きましょう!辛いテストでも Perl なら何とかな ります! (Lets write testcode! Perl enables you to provide power to write hard tests)Public/公開情報 - 29 -
  • 30. Public/公開情報 - 30 -
  • 31. 質疑をうけて、ちょっとだけ補足(発表後に追記) exit で意図せずテストが成功する場合の話ですが、これは 「no_plan」にしているときのみ発生する事象です。 比較的新しい Test::More を使っていれば、done_testing() が使えるので、それを使うべきです。また、5.8.8 とかに 標準添付される Test::More だと done_testing()が使え ないバージョンなので、その場合は no_plan をそもそも 避けるべきです。 (sorry only in Japanese)Public/公開情報 - 31 -