次の静的メソッドをテストするための最善の方法を探しています(特にDoctrineモデル)を使用):
class Model_User extends Doctrine_Record
{
public static function create($userData)
{
$newUser = new self();
$newUser->fromArray($userData);
$newUser->save();
}
}
理想的には、モックオブジェクトを使用して、「fromArray」(提供されたユーザーデータ)と「save」が呼び出されることを確認しますが、メソッドは静的であるため不可能です。
助言がありますか?
PHPUnitの作者であるSebastian Bergmannは、最近、 Stubbing and Mocking Static Methods に関するブログ投稿を行いました。 PHPUnit 3.5およびPHP 5.3および遅延静的バインディングの一貫した使用により、次のことができます。
$class::staticExpects($this->any())
->method('helper')
->will($this->returnValue('bar'));
更新:staticExpects
は PHPUnit 3.8で非推奨 であり、今後のバージョンでは完全に削除されます。
これを支援するAspectMockライブラリがあります。
https://github.com/Codeception/AspectMock
$this->assertEquals('users', UserModel::tableName());
$userModel = test::double('UserModel', ['tableName' => 'my_users']);
$this->assertEquals('my_users', UserModel::tableName());
$userModel->verifyInvoked('tableName');
Model_Userを拡張する単体テスト名前空間に新しいクラスを作成し、テストします。以下に例を示します。
元のクラス:
class Model_User extends Doctrine_Record
{
public static function create($userData)
{
$newUser = new self();
$newUser->fromArray($userData);
$newUser->save();
}
}
ユニットテストで呼び出すモッククラス:
use \Model_User
class Mock_Model_User extends Model_User
{
/** \PHPUnit\Framework\TestCase */
public static $test;
// This class inherits all the original classes functions.
// However, you can override the methods and use the $test property
// to perform some assertions.
}
ユニットテストでは:
use Module_User;
use PHPUnit\Framework\TestCase;
class Model_UserTest extends TestCase
{
function testCanInitialize()
{
$userDataFixture = []; // Made an assumption user data would be an array.
$sut = new Mock_Model_User::create($userDataFixture); // calls the parent ::create method, so the real thing.
$sut::test = $this; // This is just here to show possibilities.
$this->assertInstanceOf(Model_User::class, $sut);
}
}
静的メソッドのテストは、一般的に少し難しいと見なされます(おそらくお気づきかもしれませんが)、特にPHP 5.3。
静的メソッドを使用しないようにコードを変更できませんか?実際、なぜここで静的メソッドを使用しているのかわかりません。これはおそらくいくつかの非静的コードに書き直すことができますが、できませんか?
たとえば、次のようなことはできません:
class Model_User extends Doctrine_Record
{
public function saveFromArray($userData)
{
$this->fromArray($userData);
$this->save();
}
}
何をテストするかわからない。しかし、少なくとも静的メソッドはもうありません...
doublit ライブラリは、静的メソッドのテストにも役立ちます。
/* Create a mock instance of your class */
$double = Doublit::mock_instance(Model_User::class);
/* Test the "create" method */
$double::_method('create')
->count(1) // test that the method is called once
->args([Constraints::isInstanceOf('array')]) // test that first argument is an array
->stub('my_value') // stub the method to return "myvalue"
別の可能なアプローチは Moka ライブラリを使用することです:
$modelClass = Moka::mockClass('Model_User', [
'fromArray' => null,
'save' => null
]);
$modelClass::create('DATA');
$this->assertEquals(['DATA'], $modelClass::$moka->report('fromArray')[0]);
$this->assertEquals(1, sizeof($modelClass::$moka->report('save')));