前回の
実例を交えた使い方
Test2::V0には、
オブジェクトのモック
外部APIに接続する処理をテストする際に、
mock関数を使うと、
package Foo {
sub doit { 'A' }
}
{
my $mock = mock 'Foo' => (
override => [doit => sub { 'B' }], ――(1)
);
is +Foo->doit, 'B', '書き換えられた';
}
is +Foo->doit, 'A',
'スコープを抜けるともとのメソッドが呼ばれている';overrideに渡しています。クラスメソッドを呼び出すと上書きした値が返ってきており、
特徴的なのは、before、after、aroundのフックが登録できるようになっていることです。次のコードのようにaroundを使うことで、
my $mock = mock 'Foo' => (
before => [doit => sub { ... }],
after => [doit => sub { ... }],
around => [doit => sub {
# もとのメソッドのコードリファレンス
my $orig = shift;
# メソッドの引数
my (@args) = @_;
# もとのメソッドを実行した結果
return $orig->(@args);
}],
);
Foo->doit('foo');例外の捕捉
異常系のテストを行う際に、
例外が発生した際のメッセージの比較、
sub foo { die 'no params' unless @_ }
like dies { foo() }, qr/no params/, '例外が発生した';
ok lives { foo(1) }, '例外が発生しない';1行目では、
2行目では、dies関数に渡したブロック内で発生した例外を戻り値として、lives関数を使って例外が発生しないことをテストしています。
警告の捕捉
Perlのwarnによる警告を捕捉し、
警告が出力される関数について、
sub foo {
warn 'foo';
}
ok warns { foo() }, '警告された'; ――(1)
like warning { foo() }, qr/foo/, ┓
'警告された内容のチェック'; ┛(2)foo関数内で警告が発生したかどうかをテストしています。さらに発生した警告の内容のチェックするため、warning関数が返す値を見ています。
なお、Test2::Plugin::NoWarningsを使って、
ほかにもTest2::Tools::といったネームスペース以下にTest2用のツールセットがいくつか公開されていますので、Test2::V0が提供するものだけでは足りないと思ったときはCPAN内を検索してください。
日本語を出力する場合
テストに与える説明文として日本語を書いたときは、Wide character in printの警告が出ることがあります。
よくある回避方法として、Test::Builderで出力する際にファイルハンドルに対してエンコーディングを指定する方法があります。Test2::V0ではこのような回避は不要となり、Test2::Plugin::UTF8をあらかじめインポートしておくことで解決してくれます。
my $builder = Test::More->builder;
binmode $builder->output, ":encoding(utf8)";
binmode $builder->failure_output, ":encoding(utf8)";
binmode $builder->todo_output, ":encoding(utf8)";ただしTest2::V0をインポートしていると、Test2::Plugin::UTF8が有効になるため特に気にする必要はないのですが、
乱数のシードを設定する
Test2::V0内で有効になるプラグインTest2::Plugin::SRandでは、srandを呼び出すようになっています。テスト実行時には次のようにメッセージが出力され、
# Seeded srand with seed '20180625' from local date.デフォルトでは乱数のシードは現在日時の形式になっているため、
そこで、Test::V0がインポートされる前にTime::HiResのgettimeofdayを使ってマイクロ秒単位のエポック秒T2_に値をセットしておくことでシードとして設定されるため、
BEGIN {
use Time::HiRes qw(gettimeofday);
$ENV{T2_RAND_SEED} //= join '', gettimeofday;
}Test::Moreとの非互換なコード
ここでは、Test::Moreを使った既存のテストをTest2::V0に移行してみましょう。
多くの場合、use Test::More;している行をuseTest2::V0;に置き換えることで移行できるはずですが、
データ構造の比較―is_deeply
Test::Moreではデータ構造の比較にはisではなくis_が使われていましたが、Test2::V0で提供されるのはisのみです。ただし、
is_deeply $x, [1, 2, 3];is $x, [1, 2, 3];オブジェクトのクラスのチェック──isa_ok
Test2::V0では、
isa_ok $x, 'Foo', 'テストの説明文';isa_ok $x, ['Foo'], 'テストの説明文';
isa_ok $x, 'Foo'; # 説明文が不要の場合モジュールのロードのテスト
モジュールの文法エラーやロードした際のランタイムエラーがないことを確認するために、Test::Moreではrequire_やuse_といったテスト関数が使われていました。Test2::V0ではこれらの関数が廃止されたため、require_の代わりにrequireを直接呼び出すように変更する必要があります。モジュールのロードが失敗したときの例外によりテストは失敗するため、use_も同様の理由でuseに変更する必要があります。
<続きの
本誌最新号をチェック!
WEB+DB PRESS Vol.130
2022年8月24日発売
B5判/168ページ
定価1,628円
(本体1,480円+税10%)
ISBN978-4-297-13000-8
- 特集1
イミュータブルデータモデルで始める
実践データモデリング
業務の複雑さをシンプルに表現! - 特集2
いまはじめるFlutter
iOS/Android両対応アプリを開発してみよう - 特集3
作って学ぶWeb3
ブロックチェーン、スマートコントラクト、NFT


