SlideShare une entreprise Scribd logo
1  sur  31
Télécharger pour lire hors ligne
あんなテスト・こんなテスト        (This and That about testing)




                             土田 拓也(Takuya Tsuchida)
                                                             @tsucchi
  2011/10/15
                                                      id: tsucchi1022

 エレクトロニクス事業本部


Public/公開情報     -1-
Abstract

  テストの話をします
     (I'll be talking about testing)
  とくに「テストしにくい部分をどのようにテストするか」について話し
   ます
     (Especially, I'll talk about how to test the part which is hard to test)




Public/公開情報                                -2-
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/tsucchi



Public/公開情報                                      -3-
testcodes

  テストコード、書いてますか?
     (Do You Write testcodes?)
  テストコードとは(What is the testcode?)
              – 「入力」と「その入力に対して、期待する出力」を書いて、一致するかど
                   うかを検証するプログラム
                (programs which validates 'input' and 'expected output from the
                   provided input' are correct.)




Public/公開情報                               -4-
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-
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-
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.
  これらを、「なんとかする」やり方を紹介します
     (I'll introduce how to deal with such things)




Public/公開情報                                          -7-
   標準入出力(STDIN/STDOUT)
    コマンドラインオプション (commandline options)
    時刻(system clock)
    DB
    etc.




Public/公開情報                  -8-
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/STDERR
Public/公開情報
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 -
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 it's good idea to use this module alternate for Test::Warn)


Public/公開情報                              - 11 -
   標準入出力(STDIN/STDOUT)
    コマンドラインオプション (commandline options)
    時刻(system clock)
    DB
    etc.




Public/公開情報                  - 12 -
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/公開情報
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 -
   標準入出力(STDIN/STDOUT)
    コマンドラインオプション (commandline options)
    時刻(system clock)
    DB
    etc.




Public/公開情報                  - 15 -
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 perl's system clock)
                  • use Test::MockTime
                  • use Time::Mock
                  • CORE::GLOBAL::time() を書き換える(override
                           CORE::GLOBAL::time)



Public/公開情報
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 -
   標準入出力(STDIN/STDOUT)
    コマンドラインオプション (commandline options)
    時刻(system clock)
    DB
    etc.




Public/公開情報                  - 18 -
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 don't use ORM)
    Solution
              – データを流し込む(load data into DB)
              – Test::mysqld + something
                      • Test::Fixture::DBI
                      • Test::DBUnit
                    • Test::DataLoader::MySQL



Public/公開情報
   標準入出力(STDIN/STDOUT)
    コマンドラインオプション (commandline options)
    時刻(system clock)
    DB
    etc.




Public/公開情報                  - 20 -
exit measures(1)

  テスト中に exit が呼ばれると、意図せずテストが通ってしまう
     (If exit() is called, tests are passed accidentally)

  Example Situation
              – 他人のコードを引き継いだ際(when takeover someone's code)
              – ライブラリがエラー処理後に exit を呼んでいた(library routine calls
                   exit after error handling)
  Solution
       – exit()の上書き(override exit)
       – exit を使っている関数/メソッドの上書き(override
                   subroutine/method which uses exit)




Public/公開情報                                          - 21 -
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 unexpectedly
Public/公開情報                                - 22 -
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

     – It's OK. It should be failed.
Public/公開情報                                - 23 -
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 -
setUp/tearDown(2)

  でも書き方が変わるのは面倒くさい
     (But it isn't 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 -
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..2




Public/公開情報                                    - 26 -
Caution(1)

  今回紹介したテクニックをプロダクションコード側で使わない
     (Don't use these techniques in production code)

              – プロダクションコードでモンキーパッチしたり、時間や
                 CORE::GLOBAL::* を書き換えたり、@ARGV 書き換えた
                 り、標準入出力捕まえたりしないこと
               (In production code, don't monkey-patch, don't alter system clock, don't replace
                   CORE::GLOBAL::*, don't replace @ARGV, and don't capture STDIN/STDOUT)
              – テストでは有効なテクニックでも、プロダクションコードで使
                 うと妙なバグに振り回されるかもしれません
               (These techniques are useful in testcode, but you may encounter curious bugs if
                  using it in production code)




Public/公開情報                                      - 27 -
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 -
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 なら何とかな
    ります!
     (Let's write testcode! Perl enables you to provide power to write hard tests)




Public/公開情報                                        - 29 -
Public/公開情報   - 30 -
質疑をうけて、ちょっとだけ補足(発表後に追記)
     exit で意図せずテストが成功する場合の話ですが、これは
       「no_plan」にしているときのみ発生する事象です。

     比較的新しい Test::More を使っていれば、done_testing()
      が使えるので、それを使うべきです。また、5.8.8 とかに
      標準添付される Test::More だと done_testing()が使え
      ないバージョンなので、その場合は no_plan をそもそも
      避けるべきです。

     (sorry only in Japanese)




Public/公開情報                     - 31 -

Contenu connexe

Tendances

Java puzzlers 2013 at JavaFesta Japan
Java puzzlers 2013 at JavaFesta JapanJava puzzlers 2013 at JavaFesta Japan
Java puzzlers 2013 at JavaFesta JapanYoshio Terada
 
gen-class とバイトコード(第3回 gen-class 勉強会資料)
gen-class とバイトコード(第3回 gen-class 勉強会資料)gen-class とバイトコード(第3回 gen-class 勉強会資料)
gen-class とバイトコード(第3回 gen-class 勉強会資料)tnoda
 
Javaセキュアコーディングセミナー東京第2回演習の解説
Javaセキュアコーディングセミナー東京第2回演習の解説Javaセキュアコーディングセミナー東京第2回演習の解説
Javaセキュアコーディングセミナー東京第2回演習の解説JPCERT Coordination Center
 
配管流路の多目的最適化OpenFOAM+OpenMDAO(第28回オープンCAE勉強会@関西)
配管流路の多目的最適化OpenFOAM+OpenMDAO(第28回オープンCAE勉強会@関西)配管流路の多目的最適化OpenFOAM+OpenMDAO(第28回オープンCAE勉強会@関西)
配管流路の多目的最適化OpenFOAM+OpenMDAO(第28回オープンCAE勉強会@関西)TatsuyaKatayama
 
Pythonでの開発を効率的に進めるためのツール設定
Pythonでの開発を効率的に進めるためのツール設定Pythonでの開発を効率的に進めるためのツール設定
Pythonでの開発を効率的に進めるためのツール設定Atsushi Odagiri
 
x86とコンテキストスイッチ
x86とコンテキストスイッチx86とコンテキストスイッチ
x86とコンテキストスイッチMasami Ichikawa
 
xUnit Test Patterns - Chapter11
xUnit Test Patterns - Chapter11xUnit Test Patterns - Chapter11
xUnit Test Patterns - Chapter11Takuto Wada
 
8時間耐久PHPUnitの教室
8時間耐久PHPUnitの教室8時間耐久PHPUnitの教室
8時間耐久PHPUnitの教室Yusuke Ando
 
Javaセキュアコーディングセミナー東京第3回講義
Javaセキュアコーディングセミナー東京第3回講義Javaセキュアコーディングセミナー東京第3回講義
Javaセキュアコーディングセミナー東京第3回講義JPCERT Coordination Center
 
Javaセキュアコーディングセミナー東京第1回演習の解説
Javaセキュアコーディングセミナー東京第1回演習の解説Javaセキュアコーディングセミナー東京第1回演習の解説
Javaセキュアコーディングセミナー東京第1回演習の解説JPCERT Coordination Center
 
Cloud TPU Driver API ソースコード解析
Cloud TPU Driver API ソースコード解析Cloud TPU Driver API ソースコード解析
Cloud TPU Driver API ソースコード解析Mr. Vengineer
 

Tendances (17)

競プロでGo!
競プロでGo!競プロでGo!
競プロでGo!
 
Java puzzlers 2013 at JavaFesta Japan
Java puzzlers 2013 at JavaFesta JapanJava puzzlers 2013 at JavaFesta Japan
Java puzzlers 2013 at JavaFesta Japan
 
gen-class とバイトコード(第3回 gen-class 勉強会資料)
gen-class とバイトコード(第3回 gen-class 勉強会資料)gen-class とバイトコード(第3回 gen-class 勉強会資料)
gen-class とバイトコード(第3回 gen-class 勉強会資料)
 
Javaセキュアコーディングセミナー東京第2回演習の解説
Javaセキュアコーディングセミナー東京第2回演習の解説Javaセキュアコーディングセミナー東京第2回演習の解説
Javaセキュアコーディングセミナー東京第2回演習の解説
 
Introduction of Python
Introduction of PythonIntroduction of Python
Introduction of Python
 
Slide
SlideSlide
Slide
 
VerilatorとSystemC
VerilatorとSystemCVerilatorとSystemC
VerilatorとSystemC
 
配管流路の多目的最適化OpenFOAM+OpenMDAO(第28回オープンCAE勉強会@関西)
配管流路の多目的最適化OpenFOAM+OpenMDAO(第28回オープンCAE勉強会@関西)配管流路の多目的最適化OpenFOAM+OpenMDAO(第28回オープンCAE勉強会@関西)
配管流路の多目的最適化OpenFOAM+OpenMDAO(第28回オープンCAE勉強会@関西)
 
Pythonでの開発を効率的に進めるためのツール設定
Pythonでの開発を効率的に進めるためのツール設定Pythonでの開発を効率的に進めるためのツール設定
Pythonでの開発を効率的に進めるためのツール設定
 
x86とコンテキストスイッチ
x86とコンテキストスイッチx86とコンテキストスイッチ
x86とコンテキストスイッチ
 
xUnit Test Patterns - Chapter11
xUnit Test Patterns - Chapter11xUnit Test Patterns - Chapter11
xUnit Test Patterns - Chapter11
 
8時間耐久PHPUnitの教室
8時間耐久PHPUnitの教室8時間耐久PHPUnitの教室
8時間耐久PHPUnitの教室
 
Akka Unit Testing
Akka Unit TestingAkka Unit Testing
Akka Unit Testing
 
Javaセキュアコーディングセミナー東京第3回講義
Javaセキュアコーディングセミナー東京第3回講義Javaセキュアコーディングセミナー東京第3回講義
Javaセキュアコーディングセミナー東京第3回講義
 
Javaセキュアコーディングセミナー東京第1回演習の解説
Javaセキュアコーディングセミナー東京第1回演習の解説Javaセキュアコーディングセミナー東京第1回演習の解説
Javaセキュアコーディングセミナー東京第1回演習の解説
 
Ruby test double
Ruby test doubleRuby test double
Ruby test double
 
Cloud TPU Driver API ソースコード解析
Cloud TPU Driver API ソースコード解析Cloud TPU Driver API ソースコード解析
Cloud TPU Driver API ソースコード解析
 

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

Tokyor14 - R言語でユニットテスト
Tokyor14 - R言語でユニットテストTokyor14 - R言語でユニットテスト
Tokyor14 - R言語でユニットテストYohei Sato
 
関西Php勉強会のlimeの話
関西Php勉強会のlimeの話関西Php勉強会のlimeの話
関西Php勉強会のlimeの話Hisateru Tanaka
 
ソフトウェア工学2023 11 テスト
ソフトウェア工学2023 11 テストソフトウェア工学2023 11 テスト
ソフトウェア工学2023 11 テストToru Tamaki
 
CPANの依存モジュールをもう少し正しく検出したい
CPANの依存モジュールをもう少し正しく検出したいCPANの依存モジュールをもう少し正しく検出したい
CPANの依存モジュールをもう少し正しく検出したいcharsbar
 
テストコードの定型化
テストコードの定型化テストコードの定型化
テストコードの定型化Shinichi Hirauchi
 
Introduction to Continuous Test Runner MakeGood
Introduction to Continuous Test Runner MakeGoodIntroduction to Continuous Test Runner MakeGood
Introduction to Continuous Test Runner MakeGoodAtsuhiro Kubo
 
第4回勉強会 単体テストのすすめ
第4回勉強会 単体テストのすすめ第4回勉強会 単体テストのすすめ
第4回勉強会 単体テストのすすめhakoika-itwg
 
はこだてIKA 第4回勉強会 単体テスト
はこだてIKA 第4回勉強会 単体テストはこだてIKA 第4回勉強会 単体テスト
はこだてIKA 第4回勉強会 単体テストSeiji KOMATSU
 
10のJava9で変わるJava8の嫌なとこ!
10のJava9で変わるJava8の嫌なとこ!10のJava9で変わるJava8の嫌なとこ!
10のJava9で変わるJava8の嫌なとこ!bitter_fox
 
大規模な負荷でもドキドキしない為のJava EE
大規模な負荷でもドキドキしない為のJava EE大規模な負荷でもドキドキしない為のJava EE
大規模な負荷でもドキドキしない為のJava EETaiichilow Nagase
 
究極のバッチフレームワーク(予定)
究極のバッチフレームワーク(予定)究極のバッチフレームワーク(予定)
究極のバッチフレームワーク(予定)fumoto kazuhiro
 
20170127 JAWS HPC-UG#8
20170127 JAWS HPC-UG#820170127 JAWS HPC-UG#8
20170127 JAWS HPC-UG#8Kohei KaiGai
 
TDD勉強会キックオフ for Java
TDD勉強会キックオフ for JavaTDD勉強会キックオフ for Java
TDD勉強会キックオフ for JavaYuta Kawadai
 
新しい並列for構文のご提案
新しい並列for構文のご提案新しい並列for構文のご提案
新しい並列for構文のご提案yohhoy
 
EC-CUBE + PHPUnit で 実践テスト駆動開発
EC-CUBE + PHPUnit で 実践テスト駆動開発EC-CUBE + PHPUnit で 実践テスト駆動開発
EC-CUBE + PHPUnit で 実践テスト駆動開発Kentaro Ohkouchi
 
Pgunconf 20121212-postgeres fdw
Pgunconf 20121212-postgeres fdwPgunconf 20121212-postgeres fdw
Pgunconf 20121212-postgeres fdwToshi Harada
 
111008 silverlight square_datavalidation
111008 silverlight square_datavalidation111008 silverlight square_datavalidation
111008 silverlight square_datavalidationTakayoshi Tanaka
 
ひのきのぼうだけで全クリ目指す
ひのきのぼうだけで全クリ目指すひのきのぼうだけで全クリ目指す
ひのきのぼうだけで全クリ目指すAromaBlack
 
PostgreSQL Unconference #26 No Error on PostgreSQL
PostgreSQL Unconference #26 No Error on PostgreSQLPostgreSQL Unconference #26 No Error on PostgreSQL
PostgreSQL Unconference #26 No Error on PostgreSQLNoriyoshi Shinoda
 

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

Tokyor14 - R言語でユニットテスト
Tokyor14 - R言語でユニットテストTokyor14 - R言語でユニットテスト
Tokyor14 - R言語でユニットテスト
 
関西Php勉強会のlimeの話
関西Php勉強会のlimeの話関西Php勉強会のlimeの話
関西Php勉強会のlimeの話
 
ソフトウェア工学2023 11 テスト
ソフトウェア工学2023 11 テストソフトウェア工学2023 11 テスト
ソフトウェア工学2023 11 テスト
 
CPANの依存モジュールをもう少し正しく検出したい
CPANの依存モジュールをもう少し正しく検出したいCPANの依存モジュールをもう少し正しく検出したい
CPANの依存モジュールをもう少し正しく検出したい
 
テストコードの定型化
テストコードの定型化テストコードの定型化
テストコードの定型化
 
Introduction to Continuous Test Runner MakeGood
Introduction to Continuous Test Runner MakeGoodIntroduction to Continuous Test Runner MakeGood
Introduction to Continuous Test Runner MakeGood
 
第4回勉強会 単体テストのすすめ
第4回勉強会 単体テストのすすめ第4回勉強会 単体テストのすすめ
第4回勉強会 単体テストのすすめ
 
はこだてIKA 第4回勉強会 単体テスト
はこだてIKA 第4回勉強会 単体テストはこだてIKA 第4回勉強会 単体テスト
はこだてIKA 第4回勉強会 単体テスト
 
10のJava9で変わるJava8の嫌なとこ!
10のJava9で変わるJava8の嫌なとこ!10のJava9で変わるJava8の嫌なとこ!
10のJava9で変わるJava8の嫌なとこ!
 
大規模な負荷でもドキドキしない為のJava EE
大規模な負荷でもドキドキしない為のJava EE大規模な負荷でもドキドキしない為のJava EE
大規模な負荷でもドキドキしない為のJava EE
 
究極のバッチフレームワーク(予定)
究極のバッチフレームワーク(予定)究極のバッチフレームワーク(予定)
究極のバッチフレームワーク(予定)
 
20170127 JAWS HPC-UG#8
20170127 JAWS HPC-UG#820170127 JAWS HPC-UG#8
20170127 JAWS HPC-UG#8
 
TDD勉強会キックオフ for Java
TDD勉強会キックオフ for JavaTDD勉強会キックオフ for Java
TDD勉強会キックオフ for Java
 
新しい並列for構文のご提案
新しい並列for構文のご提案新しい並列for構文のご提案
新しい並列for構文のご提案
 
EC-CUBE + PHPUnit で 実践テスト駆動開発
EC-CUBE + PHPUnit で 実践テスト駆動開発EC-CUBE + PHPUnit で 実践テスト駆動開発
EC-CUBE + PHPUnit で 実践テスト駆動開発
 
Pgunconf 20121212-postgeres fdw
Pgunconf 20121212-postgeres fdwPgunconf 20121212-postgeres fdw
Pgunconf 20121212-postgeres fdw
 
111008 silverlight square_datavalidation
111008 silverlight square_datavalidation111008 silverlight square_datavalidation
111008 silverlight square_datavalidation
 
ひのきのぼうだけで全クリ目指す
ひのきのぼうだけで全クリ目指すひのきのぼうだけで全クリ目指す
ひのきのぼうだけで全クリ目指す
 
PostgreSQL Unconference #26 No Error on PostgreSQL
PostgreSQL Unconference #26 No Error on PostgreSQLPostgreSQL Unconference #26 No Error on PostgreSQL
PostgreSQL Unconference #26 No Error on PostgreSQL
 
emc++ chapter32
emc++ chapter32emc++ chapter32
emc++ chapter32
 

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

  • 1. あんなテスト・こんなテスト (This and That about testing) 土田 拓也(Takuya Tsuchida) @tsucchi 2011/10/15 id: tsucchi1022 エレクトロニクス事業本部 Public/公開情報 -1-
  • 2. Abstract  テストの話をします (I'll be talking about testing)  とくに「テストしにくい部分をどのようにテストするか」について話し ます (Especially, I'll 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/tsucchi Public/公開情報 -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.  これらを、「なんとかする」やり方を紹介します (I'll 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/STDERR Public/公開情報
  • 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 it's 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 perl's 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 don't use ORM)  Solution – データを流し込む(load data into DB) – Test::mysqld + something • Test::Fixture::DBI • Test::DBUnit • Test::DataLoader::MySQL Public/公開情報
  • 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 someone's 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 unexpectedly Public/公開情報 - 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 – It's 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 isn't 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..2 Public/公開情報 - 26 -
  • 27. Caution(1)  今回紹介したテクニックをプロダクションコード側で使わない (Don't use these techniques in production code) – プロダクションコードでモンキーパッチしたり、時間や CORE::GLOBAL::* を書き換えたり、@ARGV 書き換えた り、標準入出力捕まえたりしないこと (In production code, don't monkey-patch, don't alter system clock, don't replace CORE::GLOBAL::*, don't replace @ARGV, and don't 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 なら何とかな ります! (Let's write testcode! Perl enables you to provide power to write hard tests) Public/公開情報 - 29 -
  • 31. 質疑をうけて、ちょっとだけ補足(発表後に追記) exit で意図せずテストが成功する場合の話ですが、これは 「no_plan」にしているときのみ発生する事象です。 比較的新しい Test::More を使っていれば、done_testing() が使えるので、それを使うべきです。また、5.8.8 とかに 標準添付される Test::More だと done_testing()が使え ないバージョンなので、その場合は no_plan をそもそも 避けるべきです。 (sorry only in Japanese) Public/公開情報 - 31 -