unit test querybuilder kerneltestcase app php unit-testing mocking doctrine phpunit

test - PHPUnit objetos falsos y métodos estáticos



symfony test app (6)

Estoy buscando la mejor manera de probar el siguiente método estático (específicamente usando un Modelo de Doctrina):

class Model_User extends Doctrine_Record { public static function create($userData) { $newUser = new self(); $newUser->fromArray($userData); $newUser->save(); } }

Idealmente, usaría un objeto simulado para asegurarme de que se llamaba "fromArray" (con los datos de usuario suministrados) y "save", pero eso no es posible ya que el método es estático.

¿Alguna sugerencia?


Ahora está la biblioteca AspectMock para ayudar con esto:

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'');


Haría una nueva clase en el espacio de nombres de la prueba de la unidad que extendería el Model_User y lo probaría. Aquí hay un ejemplo:

Clase original:

class Model_User extends Doctrine_Record { public static function create($userData) { $newUser = new self(); $newUser->fromArray($userData); $newUser->save(); } }

Clase falsa para llamar en pruebas unitarias:

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. }

En tu prueba de unidad:

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); } }


La biblioteca doublit también podría ayudarlo a probar métodos estáticos:

/* 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"


Otro posible enfoque es con la biblioteca 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'')));


Probar métodos estáticos generalmente se considera un poco difícil (como probablemente ya habrás notado) , especialmente antes de PHP 5.3.

¿No podría modificar su código para no usar un método estático? Realmente no veo por qué estás usando un método estático aquí, de hecho; esto probablemente podría volver a escribirse en algún código no estático, ¿no es así?


Por ejemplo, podría algo como esto no hacer el truco:

class Model_User extends Doctrine_Record { public function saveFromArray($userData) { $this->fromArray($userData); $this->save(); } }

No estoy seguro de lo que probará; pero, al menos, ya no hay un método estático ...


Sebastian Bergmann, el autor de PHPUnit, recientemente publicó un blog sobre Stubbing and Mocking Static Methods . Con PHPUnit 3.5 y PHP 5.3, así como el uso constante de enlaces estáticos tardíos, puede hacer

$class::staticExpects($this->any()) ->method(''helper'') ->will($this->returnValue(''bar''));

Actualización: staticExpects está en desuso a partir de PHPUnit 3.8 y se eliminará por completo con las versiones posteriores.