ぱいぱいにっき

Pythonが好きすぎるけれど、今からPerlを好きになりますにっき

テストこわい

どうも、日々ヒリヒリしてますか。@mackee_w/マコピーです。

この記事はHachioji.pm #25の発表資料も兼ねています。

テストはこわくない!

たぶんみなさんガチテスターで以下のことは常識というか、「は?」と思われるのではないかと想定しますが温かい目で見ていただけると幸いです。

Hachioji.pmのatndページから引用なんですがこんなことが書かれていて、

今回お題はテストです、テストこわい
勿論お題を無視いただいて、自由な発表をしていただいても結構です!

えー、線を引いたとこですね。
テストこわい、と。
テストつらい、と。
でもそんなこと無いんですよね、テストはこわくないです。

テストをこわくなくするための身構え

テストこわくないです。もしあなたが朝パンをくわえて「あー納期ヤバイ納期ヤバイ」なんて呟きながら走ってたら曲がり角でテストちゃんとぶつかったとしましょう。こいつを回避するには。

人は失敗して成長する

失敗はこわくない! not okなんて言われても死ぬわけじゃない!
そう言い聞かせておもむろにテストを走らせます。すると言われるわけです。

$ prove test_me_spec.t
test_me_spec.t .. TestMe.pm did not return a true value at test_me_spec.t line 8.
BEGIN failed--compilation aborted at test_me_spec.t line 8.
test_me_spec.t .. Dubious, test returned 255 (wstat 65280, 0xff00)
No subtests run

Test Summary Report
-------------------
test_me_spec.t (Wstat: 65280 Tests: 0 Failed: 0)
Non-zero exit status: 255
Parse errors: No plan found in TAP output
Files=1, Tests=0, 0 wallclock secs ( 0.03 usr 0.01 sys + 0.04 cusr 0.00 csys = 0.08 CPU)
Result: FAIL

え? not okですらでない?
TestMe.pmのコードはこちら

package TestMe;

use Mouse;

has 'status' => (
    is => 'ro',
    isa => 'Int',
    required => 1,
);

いっちょまえにMouse使ってます。一見動きそうだけれど……。テストがおかしいのかなー。
一方test_me_spec.t

use strict;
use warnings;
use utf8;

use Test::More;
use TestMe;

my $test_me = TestMe->new();

is $test_me->status, 1;

done_testing();

こっちもおかしくない。なんでかなー。

_人人人人人人人人人人人人人人_
> 人はハマる。だからテスト <
 ̄Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y ̄

テストの結果をもう一度見る。

test_me_spec.t .. TestMe.pm did not return a true value at test_me_spec.t line 8.

ウッ、そうか。

@@ -7,3 +7,5 @@
has 'status' => (
     is => 'ro',
     isa => 'Int',
     required => 1,
 );
+
+1;

Perlの罠、モジュールは最後に1を返さないと死ぬ!!! 忘れてた。

よしこれで走らせよう!

$ prove test_me_spec.t
test_me_spec.t .. Attribute (status) is required at test_me_spec.t line 10
test_me_spec.t .. Dubious, test returned 255 (wstat 65280, 0xff00)
No subtests run
Test Summary Report
-------------------
test_me_spec.t (Wstat: 65280 Tests: 0 Failed: 0)
Non-zero exit status: 255
Parse errors: No plan found in TAP output
Files=1, Tests=0, 0 wallclock secs ( 0.03 usr 0.01 sys + 0.03 cusr 0.00 csys = 0.07 CPU)
Result: FAIL

٩(๑❛ᴗ❛๑)۶わーい、また死んだー
まあrequired指定してるからテストで書けよって話なんですが、もっと複雑なモジュールとかアプリケーションをテストするときに、プリントデバッグで変数追っかけたりするのやってられないので、じゃあ振る舞いを書いたテストを書けばええヤーン、という感じです。

詳しくは以下の本。PythonとかJavaだけれど

テスト駆動開発入門

テスト駆動開発入門

  • 作者: ケントベック,Kent Beck,長瀬嘉秀,テクノロジックアート
  • 出版社/メーカー: ピアソンエデュケーション
  • 発売日: 2003/09
  • メディア: 単行本
  • 購入: 44人 クリック: 1,029回
  • この商品を含むブログ (156件) を見る

いやワシ手動デバッグするし完璧やけえテストとかいらんわ迷惑やわ

そんなあなたの回避方法。

  1. SKIP、TODOで囲む
use strict;
use warnings;
use utf8;

use Test::More;
use TestMe;

TODO: {
    todo_skip 'i\'m afraid to test', 1;
    my $test_me = TestMe->new(status => 0);

    is $test_me->status, 1;
};

done_testing();

これ通ります。SKIP、TODOブロック内で特殊な書き方するとテストこけても成功したことにしてくれます。
修正主義ばんざい。
ちなみにSKIPとTODOの使い分けですが、
Test::More - テストを書くためのもう一つのフレームワーク - perldoc.jp

もし、ユーザが出来そうにないときには、SKIPを使ってください。 これには、インストールされていないオプショナルなモジュールや、 (fork()やsymlinksなどの)機能を持っていないOSで実行することや、 インターネット接続を必要としているのに、それをユーザが利用できないことも含みます。

もし、プログラマがまだ、やっていないときには、TODO を使ってください。 これは、テストscriptに、テストを置きたい(常によい考えです)けれども、 まだ書いていないコードや、まだ直していないバグなどです。

だそうです。つまり上のテストは「直す気がある」ことになります。Perlって挙動一緒だけれど書き方で意思を表明すること、ありますよね。

2. Test::Successful

All Test::Successful - Perl Advent Calendar Japan 2011 Test Track
アルパカとテストとAcmeモジュー - Perl Advent Calendar Japan 2011 Acme Track
一昨年のPerl Advent Calendarに出た両記事。
Test::Successfulを使えばTestが通らない日も安心です。

そんなわけで

テストはちゃんと書きましょう!!!!!!!!!!!!!!111111
回避しちゃダメです、あいつらいいやつだから!!!!!!!!!!!!11