2070


`open`がまだ2引数でベアワードを織り交ぜていた頃のメール送信プログラムがあります。 このメールのメッセージをテストするスクリプトを書こうとしています。

一部だけ抜粋するとこのような感じになります:

[code]

    require 'jcode.pl';
    require 'mimew.pl';
    
    open(FH, '| sendmail -t -oi');
    print FH &mimeencode("From: $from") . "\n";
    print FH &mimeencode("To: $to") . "\n";
    print FH qq{Content-Type: text/plain; charset="iso-2022-jp"\n};
    print FH &mimeencode("Subject: $subject") . "\n";
    print FH "\n";
    foreach $line (@lines) {
        print FH &jcode::jis($line, 'sjis') . "\n";
    }
    close(FH);
    
[/code]

とりあえずざっくりと、テストスクリプトが対象のコードを舐めた時に実際にメールを送ってしまわないように、`open`にsendmailらしきコマンドが渡されたら黙って`1`を返すよう以下のようなコードをテストに含めました。

しかし、そこから一歩進んでファイルハンドルに書き込まれた内容を評価する方法が分かりません。

[code]

    BEGIN {
        use Symbol ();
        *CORE::GLOBAL::open = sub : prototype(*;$@) {
            no strict 'refs';
            $_[0] = defined $_[0] ? $_[0] : Symbol::qualify($_[0], scalar caller);
            return CORE::open($_[0]) if @_ == 1;
            return 1 if $_[1] =~ /sendmail/;
            return CORE::open($_[0], $_[1]) if @_ == 2;
            return 1 if $_[2] =~ /sendmail/;
            return CORE::open($_[0], $_[1], $_[2]) if @_ == 3 && defined $_[2];
            return CORE::open($_[0], $_[1], undef) if @_ == 3;
            return CORE::open($_[0], $_[1], @_[2..$#_]);
        };
    }
    
[/code]

以下の条件を満たしつつファイルハンドルに書き出された文字列をテストスクリプトの中で変数に代入することは可能でしょうか？
また、可能であればどのように実現できますか？

  * テスト実行時に実際にメールを送信させてしまわないこと。
  * スクリプトが他で使っているsendmailと関係のない`open`を壊さないこと。
  * テスト対象のスクリプトをいじらない事。


CC BY-SA 3.0
2014-12-18T18:18:22.470
2062
2014-12-20T11:56:19.563
2014-12-20T11:56:19.563
33
62
question
テスト perl sendmail mock
古いCGIに残る`open(FH, '| sendmail -t -oi')`をテストしたい


単純にCORE::openの`$_[0]`の中を覗けばよいのではないでしょうか？
無論、`$_[1]`または`$_[2]`にsendmailという文字があればという条件式をつけて。


CC BY-SA 3.0
2014-12-18T23:44:40.410
2066
2014-12-18T23:44:40.410
3709
2062
answer


CORE を直接弄るよりは、テスト時のみ sendmail への PATH を書き換えてそちらが標準入力から得た内容でテストした方が健全な気がします。


CC BY-SA 3.0
2014-12-19T01:13:12.143
2070
2014-12-19T01:13:12.143
440
2062
answer


`return 1` している部分で `return CORE::open($_[0], "> out.txt") if $_[1] =~
/sendmail/ || $_[2] =~ /sendmail/;` のようにファイルに書き出すようにしておけば後でファイルから変数に読み込めます。


CC BY-SA 3.0
2014-12-19T08:21:26.567
2121
2014-12-19T08:21:26.567
5044
2062
answer