静的メソッド呼び出しをエミュレートするPHPUnitのモックオブジェクト?
質問
データベース内のデータアクセスを管理するクラスをテストしようとしています(基本的にはCRUDです)。使用しているDBライブラリには、静的な呼び出しで最初にテーブルオブジェクトを取得するAPIがあります:
function getFoo($id) {
$MyTableRepresentation = DB_DataObject::factory("mytable");
$MyTableRepresentation->get($id);
... do some stuff
return $somedata
}
...アイデアが得られます。
このメソッドをテストしようとしていますが、(a)テストに実際のdb接続が不要で、(b)DB_DataObject libを含める必要さえないように、DataObjectのものをモックしています。テスト用。
ただし、PHPUnitでは、静的呼び出しを適切に設定するために$ this-<!> gt; getMock()を取得することはできません。私が持っている...
$DB_DataObject = $this->getMock('DB_DataObject', array('factory'));
...しかし、テストではまだ不明なメソッド<!> quot; factory <!> quot;と表示されます。オブジェクトを作成していることは知っています。なぜなら、DB_DataObjectが見つからなかったと言っていたからです。今ではできます。しかし、方法はありませんか?
私が本当にやりたいことは、2つのモックオブジェクトを作成することです。1つは返されるテーブルオブジェクト用です。そのため、ファクトリが静的呼び出しであることを指定する必要があるだけでなく、既に設定されている指定された他のモックオブジェクトを返すことも必要です。
私はしばらく前にSimpleTestでこれを行った(コードが見つからない)という警告として言及する必要があり、正常に動作しました。
何が得られますか
[更新]
expects()と関係があることを理解し始めています
解決
静的な呼び出しを使用しない方が良いという点で、あなたとあなたの両方に同意します。ただし、DB_DataObjectはサードパーティのライブラリであり、静的呼び出しはコードの使用法ではなく、それらのベストプラクティスであることを忘れていたと思います。返されたオブジェクトを直接構築することを含む、オブジェクトを使用する他の方法があります。そのDB_DOクラスを使用しているクラスファイルに、それらのかっこいいinclude / requireステートメントを残すだけです。テスト中に同じ名前のクラスをモックしようとすると、テストが壊れる(または分離されない)ので、少なくともそれは残念です。
他のヒント
ライブラリを変更できない場合は、ライブラリへのアクセスを変更してください。 DB_DataObject :: factory()へのすべての呼び出しをコード内のインスタンスメソッドにリファクタリングします。
function getFoo($id) {
$MyTableRepresentation = $this->getTable("mytable");
$MyTableRepresentation->get($id);
... do some stuff
return $somedata
}
function getTable($table) {
return DB_DataObject::factory($table);
}
テストするクラスの部分的なモックを使用して、getTable()がモックテーブルオブジェクトを返すようにすることができます。
function testMyTable() {
$dao = $this->getMock('MyTableDao', array('getMock'));
$table = $this->getMock('DB_DataObject', ...);
$dao->expects($this->any())
->method('getTable')
->with('mytable')
->will($this->returnValue($table));
$table->expects...
...test...
}
これは、コード内の依存関係の良い例です-デザインにより、実際のクラスではなくMockを挿入することができなくなりました。
最初の提案は、静的呼び出しではなくインスタンスを使用するようにコードをリファクタリングすることです。
DB_DataObjectクラスにない(またはない)ものは、ファクトリメソッドを呼び出す前に準備されたdbオブジェクトを渡すセッターです。そうすれば、必要に応じて、モックまたはカスタムdbオブジェクト(同じインターフェースを使用)を渡すことができます。
テストのセットアップ:
public function setUp() {
$mockDb = new MockDb();
DB_DataObject::setAdapter($mockDb);
}
factory()メソッドは、模擬DBインスタンスを返す必要があります。クラスにまだ統合されていない場合、おそらくfactory()メソッドをリファクタリングして機能させる必要があります。
テストケースにDB_DataObjectのクラスファイルが必要か/含まれていますか? PHPUnitがオブジェクトをモックしようとする前にクラスが存在しない場合、このようなエラーが発生する可能性があります。
PHPUnit MockFunction拡張機能とrunkitを使用して、静的メソッドをモックすることもできます。モンキーパッチであるため、極端な場合にのみ使用する必要があるため、注意してください。優れたプログラミング慣行を代用しません。