2012-02-17 12 views
11

モックオブジェクトを作成する必要があります。モックオブジェクトは、インスタンス化時にコードベースでelsewareするためにプロパティのデフォルトセットで作成する必要があります。デフォルトプロパティを持つモックオブジェクトの作成

$mock = $this->getMock('MyClass', array(), array(), 'MyClass_Mock'); 
$mock->prop = 'foobar'; 

$myclassMock = new get_class($mock); 
var_dump($myclassMock->prop); // NULL 
// How can I make this dump 'foobar' ? 

私は、決定見つけ、そしてそのテストの目的を台無しにしてしまう嘲笑オブジェクトを注入し、これらのクラスをインスタンス化するフレームワークの一部をテストしています。

私は動的にそうように嘲笑クラスを作成します。..任意のメソッドをモックする必要はありません。

class MyClass_Mock extends MyClass { 
    public $prop = 'foobar'; 
} 

編集:簡単な例

+0

だけ明確にするため、あなたが実際に嘲笑されているクラスをインスタンス化せず、そのクラスのデフォルトのプロパティを既存のクラスをモック、そしてあなたのモックを与えたいですか? – Leigh

+0

@Leigh右、クラスはフレームワークのより深くインスタンス化されます。私が嘲笑しているクラスは抽象モデルです。実際のモデルのように動作するように '$ fields'をいくつか与えたいと思います。私はPHPUnitがコードを文字列に書いてevaling()してモックを作成することを知っています。私はちょうどそのプロセスにプロパティ宣言を含める方法がわかりません。 –

答えて

4

あなたはリフレクションを使用して感じはどうすればよいですか?

$r = new ReflectionClass('MyClass'); 

$props = $r->getDefaultProperties(); 

$mock = new stdClass; 

foreach ($props as $prop => $value) { 
    $mock->$prop = $value; 
} 

Reflectionを自分自身ではなく、基本的なイントロスペクションに使用しました。私は可視性などを完全に模倣できるかどうかは分かりませんが、文字列への書き込みのルートを続けるとどうしていいのでしょうか?eval ing。

編集:あなたは、動的に構築する場合には好奇心のうち反射機能によってスキャンさ

、完全に完全な可視性の制約、定数、および静的な要素適切に実施し、ダミーのメソッドを持つクラスを模倣することは全く可能です文字列のクラスとevalです。

、ダウンし、正しいデータ型を得るために来るときは本当に完全に(あなたが例えば配列から配列コンストラクターを再構築するためのコードが必要になります)、すべての可能性をサポートするための完全な使命になりますように見えますがあなたはこのルートを下る場合、私は今:)倹約して喜んだより

は運のベスト、それはより多くの脳力を必要と

ここでは、コードの少しですが、あなたは定数と同じことを行うことができ、同様の方法で空のメソッドを作成します。

class Test 
{ 
    private static $privates = 'priv'; 
    protected $protected = 'prot'; 
    public $public = 'pub'; 
} 

$r = new ReflectionClass('Test'); 

$props = $r->getDefaultProperties(); 

$mock = 'class MockTest {'; 

foreach ($props as $prop => $value) { 
    $rProp = $r->getProperty($prop); 


    if ($rProp->isPrivate()) { 
     $mock .= 'private '; 
    } 
    elseif ($rProp->isProtected()) { 
     $mock .= 'protected '; 
    } 
    elseif ($rProp->isPublic()) { 
     $mock .= 'public '; 
    } 

    if ($rProp->isStatic()) { 
     $mock .= 'static '; 
    } 

    $mock .= "$$prop = "; 

    switch (gettype($value)) { 
     case "boolean": 
     case "integer": 
     case "double": 
      $mock .= $value; 
      break; 
     case "string": 
      $mock .= "'$value'"; 
      break; 
/* 
"array" 
"object" 
"resource" 
*/ 
    case "NULL": 
      $mock .= 'null'; 
      break; 
    } 

    $mock .= ';'; 
} 

$mock .= '}'; 

eval($mock); 

var_dump(new MockTest); 
+2

できれば2倍upvoteしたいと思います。努力をしてくれてありがとう..私はこれまでの反射経路を試していないが、面白いと思う。私はあなたの提案のいくつかを試して、それがどうなるか見てみましょう:) –

3

私はあなたがさえはテスト目的のためにこれを行うためにが必要かわかりません。

通常、モデルアクセスを含むコードをテストするときは、実際のモデルを模擬するのではなく、フィクスチャを使用します。なぜなら、モデルはモックされる必要のある機能を公開していない「ダム」データ構造だからです。

あなたの例では、これが影響しています:動作(メソッド)をモックする必要がない場合は、模擬オブジェクトは必要ありません。モデルがそのデータソースとして使用する代わりに、データフィクスチャが必要です。あなたが言うように、"依存性注入はオプションではありません"の場合に特に当てはまります。

とにかくモデルを模倣したいと思ったら、@ Leighの反射ソリューションを提案したいと思います。

私はちょうどあなたが少しのためのより多くの詳細をチェックアウト可能性があることを昨日のデータベースのテストについての質問に答え:私は問題では、システム、被試験を持っていなければならないということだと思います PHPUnit: How to test database interactions on remote Postgres server?

+0

良い点。ダイナミックなフィクスチャーを作成しようとしていると言えるでしょう。私は、模造モデルを作成して基礎となるモデルフレームワークをテストしようとしています。私たちのモデルはほとんど全てが保護されたプロパティで構成されているので、 '$ _fields = array( 'firstname、' lastname ');'を使うだけでユーザモデルを作成できます。私の目標は、基礎となるフレームワークをテストするために偽のモデルを動的に構築することによって、あらゆる状況を再現する能力を持つことです。私はすでにデータ・ゲートウェイとフレームワークの残りの部分を嘲笑しました..私は単にデフォルトの小道具私が見る –

+0

なるほどと動的なクラスを作成する機能が必要です。その場合は、是非、それらのモデルを模擬してください。一般的にはそのようなもので、私は、単一の保護されたアレイ内のすべてのプロパティを保存し、「コレクション」のオブジェクトモデルのベースと、プロパティの読み取りは/簡単な記述にするために魔法 '__get'と' __set'と 'ArrayAccess'を実装すると思います。もしあなたがそうしたならば、あなた自身の 'Model :: load'メソッドを投げ込んで、キー/値の配列からモデルを一筆書きで入れることができます。そのような 'load'メソッドは、あなたが望む情報をオブジェクトに簡単に入れさせるでしょう。さらに、必要に応じて、検証などの子クラスによって拡張することもできます。 – rdlowrey

1

を(あなたのフレームワーク)が可能newを使用してモデルオブジェクトを直接インスタンス化することができ、各テストではそのプロパティのデフォルト値を別々に設定する必要があります。

このような場合は、建設時にプロパティの定義済みのセットを移入するために、単純な基本クラスを作成することができます。以下のソリューションはPHP 5.3のlate static bindingを使用していますが、わずかな変更を加えなくても簡単に同じ結果が得られます。

class MockModel 
{ 
    public static $properties; 

    public function __construct() { 
     if (isset(static::$properties) && is_array(static::$properties)) { 
      foreach (static::$properties as $key => $value) { 
       $this->$key = $value; 
      } 
     } 
    } 
} 

class MockBook extends MockModel { /* nothing needed */ } 

function testBookWithTitle() { 
    MockBook::$properties = array(
     'title' => 'To Kill a Mockingbird' 
    ); 
    $book = new MockBook; 
    self::assertEquals('To Kill a Mockingbird', $book->title); 
} 

は、限り、あなたはあなたのフレームワークにnewで使用するクラス名を提供することができますように、これは動作するはずです。あなたのフレームワークへの単一の呼び出し中に同じモッククラスの複数のインスタンスを作成できるようにする必要がある場合は、インデックス機構のいくつかの並べ替えで上記を強化する必要があります。

+0

モデルテスト用です。私は偽の著者と書籍のモデルを作り、その関係をテストしたいと思っています。私は、フレームワークbooks' '$ですauthor->を使用すると、新しい' Book'オブジェクトをインスタンス化し、データとそれをシードとする/ author'の 'から関係基準を決定するために、そのプロパティを読み取る必要があります。そうではありません、私は実際に私の擬似 'Book'オブジェクトをどこにでも注入することができません。なぜなら、これらのオブジェクトを動的にインスタンス化するフレームワークなのでです。私はちょうどそのコードでそのクラスを定義することなく、それらのプロパティを持つ 'Author'クラスをメモリに投げる必要があります。 –

+0

質問の最後の例を見てください。私はちょうどそれをどこでもハードコーディングせずにメモリにそれらの種類のクラスを書くことができる必要があります。私はPHPUnitのMock Object Builderを活用できると思っていましたが、その機能を持っているかどうかはわかりません。 –

+0

@MikeB - 私の更新を参照してください。これはあなたが達成しようとしているものですか? –

関連する問題