PHP の標準入力を上書きする方法を教えてください。


cli で起動する PHP スクリプトで、次のように標準入力を取得し処理するものがあります。
<?php
class Foo
{
function main()
{
$stdin_data = file_get_contents("php://stdin");
if (preg_match("/regex/", $stdin_data)) {
return true;
} else {
return false;
}
}
}
?>

これの単体試験を行うため、テストケースを作りたいと思っています。
そのためテストケース中で、上述したスクリプト中の $stdin_data という変数に任意のデータを入れたいのですが、標準入力ストリームを上書きする方法がわかりません。

$stdin_data に任意のデータを入れる方法を教えてください。

回答の条件
  • 1人2回まで
  • 登録:
  • 終了:2009/10/05 10:33:21
※ 有料アンケート・ポイント付き質問機能は2023年2月28日に終了しました。

ベストアンサー

id:makeworld No.3

回答回数75ベストアンサー獲得回数23

ポイント100pt

どちらもclass Fooを若干変更する必要があるのですが、こんな感じでいかがでしょう?

  • Foo::main()の引数にファイル名を指定
<?php
class Foo {
  function main($filename = "php://stdin") {
    if($filename != "php://stdin") {
      print "WARNING: filename = ($filename)\n";
    }
    $stdin_data = file_get_contents($filename);
    if (preg_match("/regex/", $stdin_data)) {
      return true;
    } else {
      return false;
    }
  }
}
$foo =& new Foo();

$result = $foo->main("./case1.txt");
print "case1 = ($result)\n";

$result = $foo->main("./case2.txt");
print "case2 = ($result)\n";
?>
  • file_get_contents()を自前の関数でラップ
<?php
$MY_STDIN = "php://stdin";
function my_file_get_contents() {
  global $MY_STDIN;

  if($MY_STDIN != "php://stdin") {
    print "WARNING: MY_STDIN = ($MY_STDIN)\n";
  }
  return file_get_contents($MY_STDIN);
}

class Foo {
  function main() {
    $stdin_data = my_file_get_contents();
    if (preg_match("/regex/", $stdin_data)) {
      return true;
    } else {
      return false;
    }
  }
}
$foo =& new Foo();

$MY_STDIN = "./case1.txt";
$result = $foo->main();
print "case1 = ($result)\n";

$MY_STDIN = "./case2.txt";
$result = $foo->main();
print "case2 = ($result)\n";
?>
id:rootinwerk

実はテスト対象のクラス(Foo)の入力部分を変更してしまうということも少し考えていました。

しかし上手く動かすアイデアが思いつかなかったことと、元クラスに手を入れるのに少し勇気が要るので、まずはテストケースだけで完結できないかと考えていました!!

どうしても完結できなかったら、この方法で試してみたいと思います!!

ありがとうございます!!

2009/10/03 20:51:18

その他の回答2件)

id:GoldenDawn No.1

回答回数426ベストアンサー獲得回数81

ポイント50pt

状況がよく分からないのですが、テストデータをファイル (test.dat など) で用意しておいて、

php hoge.php < test.dat

のようにリダイレクトで渡すのではどうでしょうか。

id:rootinwerk

PHPUnit や SimpleTest を利用し、テストケースは PHP だけで簡潔させたいと思っているため、シェルのリダイレクトを利用することができません。

次の様なテストケースを書きたいです。

(これだと file_put_contents のところで失敗するんですけど、やりたいことは分かると思います。)

class FooTestCase extends SimpleTest

{

var $Foo = null;

class __construct()

{

$this->Foo =& new Foo();

}

class main()

{

file_put_contents("php://stdin", "hogehoge\nregex\n");

$result = $this->Foo->main();

$this->assertTrue($result);

}

}

?>

2009/10/02 16:44:11
id:i4ooon No.2

回答回数56ベストアンサー獲得回数20

ポイント100pt

いろいろ試しましたが、難しいですね。

同じようなことをやろうとした人がいます、

http://d.hatena.ne.jp/heavenshell/20090129/1233230514

知ってるのかもだが、phptというテストフレームワークもあるんすね。

レシピファイルみたいなとこに

  • STDIN--

として記述してやれば良いみたい。

これも純粋なphpの記述じゃないからダメなんすかね?

ま、シェル書くのと何が違うのって言われりゃ、シェルよりはphpと親和性高いんじゃないのくらいだけど。

id:rootinwerk

phpt というものがあるんですね!!

組み込んでいけるかもしれません!!

試してみます!!

2009/10/03 20:41:32
id:makeworld No.3

回答回数75ベストアンサー獲得回数23ここでベストアンサー

ポイント100pt

どちらもclass Fooを若干変更する必要があるのですが、こんな感じでいかがでしょう?

  • Foo::main()の引数にファイル名を指定
<?php
class Foo {
  function main($filename = "php://stdin") {
    if($filename != "php://stdin") {
      print "WARNING: filename = ($filename)\n";
    }
    $stdin_data = file_get_contents($filename);
    if (preg_match("/regex/", $stdin_data)) {
      return true;
    } else {
      return false;
    }
  }
}
$foo =& new Foo();

$result = $foo->main("./case1.txt");
print "case1 = ($result)\n";

$result = $foo->main("./case2.txt");
print "case2 = ($result)\n";
?>
  • file_get_contents()を自前の関数でラップ
<?php
$MY_STDIN = "php://stdin";
function my_file_get_contents() {
  global $MY_STDIN;

  if($MY_STDIN != "php://stdin") {
    print "WARNING: MY_STDIN = ($MY_STDIN)\n";
  }
  return file_get_contents($MY_STDIN);
}

class Foo {
  function main() {
    $stdin_data = my_file_get_contents();
    if (preg_match("/regex/", $stdin_data)) {
      return true;
    } else {
      return false;
    }
  }
}
$foo =& new Foo();

$MY_STDIN = "./case1.txt";
$result = $foo->main();
print "case1 = ($result)\n";

$MY_STDIN = "./case2.txt";
$result = $foo->main();
print "case2 = ($result)\n";
?>
id:rootinwerk

実はテスト対象のクラス(Foo)の入力部分を変更してしまうということも少し考えていました。

しかし上手く動かすアイデアが思いつかなかったことと、元クラスに手を入れるのに少し勇気が要るので、まずはテストケースだけで完結できないかと考えていました!!

どうしても完結できなかったら、この方法で試してみたいと思います!!

ありがとうございます!!

2009/10/03 20:51:18

コメントはまだありません

この質問への反応(ブックマークコメント)

「あの人に答えてほしい」「この質問はあの人が答えられそう」というときに、回答リクエストを送ってみてましょう。

これ以上回答リクエストを送信することはできません。制限について

回答リクエストを送信したユーザーはいません