いくつかの古いスクリプトに単体テストを追加する必要があります。スクリプトはすべて基本的に次の形式です。
#!/usr/bin/perl
# Main code
foo();
bar();
# subs
sub foo {
}
sub bar {
}
単体テストでこのコードを「要求」しようとすると、コードのメインセクションが実行されますが、「foo」を単独でテストできるようにしたいのです。
foo、barを別の.pmファイルに移動せずにこれを行う方法はありますか?
いくつかの古いスクリプトに単体テストを追加する必要があります。スクリプトはすべて基本的に次の形式です。
#!/usr/bin/perl
# Main code
foo();
bar();
# subs
sub foo {
}
sub bar {
}
単体テストでこのコードを「要求」しようとすると、コードのメインセクションが実行されますが、「foo」を単独でテストできるようにしたいのです。
foo、barを別の.pmファイルに移動せずにこれを行う方法はありますか?
セキュリティ上の懸念がないと仮定して、サブ { ... } でラップし、評価します。
use File::Slurp "read_file";
eval "package Script; sub {" . read_file("script") . "}";
is(Script::foo(), "foo");
(eval が、スクリプトによってクローズされるレキシカルの範囲内にないことに注意してください)。
単体テスト スクリプトのもう 1 つの一般的なトリックは、コードの本体を「呼び出し元」ブロックにラップすることです。
#!/usr/bin/perl
use strict;
use warnings;
unless (caller) {
# startup code
}
sub foo { ... }
コマンドライン、cron、bash スクリプトなどから実行すると、正常に動作します。ただし、別の Perl プログラムからロードすると、「unless (caller) {...}」コードは実行されません。次に、テスト プログラムで名前空間を宣言し (スクリプトはおそらくパッケージ main:: のコードを実行しているため)、スクリプトを実行します。
#!/usr/bin/perl
package Tests::Script; # avoid the Test:: namespace to avoid conflicts
# with testing modules
use strict;
use warnings;
do 'some_script' or die "Cannot (do 'some_script'): $!";
# write your tests
「do」は eval よりも効率的であり、これについてはかなりクリーンです。
スクリプトをテストするためのもう 1 つのトリックは、Expectを使用することです。これはよりクリーンですが、使用するのも難しく、何かをモックアップする必要がある場合にスクリプト内で何かをオーバーライドすることはできません。
ああ、古い「プログラムを単体テストするにはどうすればよいですか」という質問。最も簡単なトリックは、プログラムが処理を開始する前にこれをプログラムに入れることです。
return 1 unless $0 eq __FILE__;
__FILE__
現在のソースファイルです。 $0
実行中のプログラムの名前です。それらが同じ場合、コードはプログラムとして実行されています。それらが異なる場合は、ライブラリとしてロードされています。
プログラム内のサブルーチンの単体テストを開始するには、これで十分です。
require "some/program";
...and test...
次のステップは、サブルーチンの外側にあるすべてのコードを に移動するmain
ことです。これを行うことができます。
main() if $0 eq __FILE__;
これで、他のサブルーチンと同じように main() をテストできます。
それが完了したら、プログラムのサブルーチンを独自の実際のライブラリに移動することを検討し始めることができます。