tutorial pruebas example español ejecutar descargar php mocking phpunit

pruebas - phpunit tutorial



Simulacro en PHPUnit-configuración múltiple del mismo método con diferentes argumentos (6)

Mis 2 centavos para el tema: preste atención al usar at ($ x): significa que la llamada al método esperada será la llamada al método ($ x + 1) th en el objeto simulado; no significa que será la llamada ($ x + 1) th del método esperado. Esto me hizo perder algo de tiempo, así que espero que no te acompañe. Saludos a todos.

¿Es posible configurar PHPUnit simulado de esta manera?

$context = $this->getMockBuilder(''Context'') ->getMock(); $context->expects($this->any()) ->method(''offsetGet'') ->with(''Matcher'') ->will($this->returnValue(new Matcher())); $context->expects($this->any()) ->method(''offsetGet'') ->with(''Logger'') ->will($this->returnValue(new Logger()));

Uso PHPUnit 3.5.10 y falla cuando pregunto por Matcher porque espera el argumento "Logger". Es como si la segunda expectativa es reescribir la primera, pero cuando la elimino, todo se ve bien.



Puede lograr esto con una devolución de llamada:

class MockTest extends PHPUnit_Framework_TestCase { /** * @dataProvider provideExpectedInstance */ public function testMockReturnsInstance($expectedInstance) { $context = $this->getMock(''Context''); $context->expects($this->any()) ->method(''offsetGet'') // Accept any of "Matcher" or "Logger" for first argument ->with($this->logicalOr( $this->equalTo(''Matcher''), $this->equalTo(''Logger'') )) // Return what was passed to offsetGet as a new instance ->will($this->returnCallback( function($arg1) { return new $arg1; } )); $this->assertInstanceOf( $expectedInstance, $context->offsetGet($expectedInstance) ); } public function provideExpectedInstance() { return array_chunk(array(''Matcher'', ''Logger''), 1); } }

Debería pasar por cualquier argumento "Logger" o "Matcher" pasado al método offsetGet Context Mock:

F:/Work/code/gordon/sandbox>phpunit NewFileTest.php PHPUnit 3.5.13 by Sebastian Bergmann. .. Time: 0 seconds, Memory: 3.25Mb OK (2 tests, 4 assertions)

Como puede ver, PHPUnit ejecutó dos pruebas. Uno para cada valor de DataProvider. Y en cada una de esas pruebas hizo la aserción para with() y la de instanceOf , por lo tanto, cuatro aserciones.


Siguiendo con la respuesta de @edorian y los comentarios (@MarijnHuizendveld) con respecto a asegurar que se llame al método tanto con Matcher como con Logger, y no simplemente dos veces con Matcher o Logger, aquí hay un ejemplo.

$expectedArguments = array(''Matcher'', ''Logger''); $context->expects($this->exactly(2)) ->method(''offsetGet'') ->with($this->logicalOr( $this->equalTo(''Matcher''), $this->equalTo(''Logger'') )) ->will($this->returnCallback( function($param) use (&$expectedArguments){ if(($key = array_search($param, $expectedArguments)) !== false) { // remove called argument from list unset($expectedArguments[$key]); } // The first arg will be Matcher or Logger // so something like "return new $param" should work here } )); // perform actions... // check all arguments removed $this->assertEquals(array(), $expectedArguments, ''Method offsetGet not called with all required arguments'');

Esto es con PHPUnit 3.7.

Si el método que está probando en realidad no devuelve nada, y simplemente necesita probar que se lo llama con los argumentos correctos, se aplica el mismo enfoque. Para este escenario, también intenté hacer esto usando una función de devolución de llamada para $ this-> callback como el argumento para con, en lugar de returnCallback en el testamento. Esto falla, ya que internamente phpunit llama a la devolución de llamada dos veces en el proceso de verificación de la devolución de llamada del emparejador de argumento. Esto significa que el enfoque falla, ya que en la segunda llamada ese argumento ya ha sido eliminado de la matriz de argumentos esperados. No sé por qué phpunit lo llama dos veces (parece un desperdicio innecesario), y supongo que podría solucionarlo quitándolo solo en la segunda llamada, pero no tenía la suficiente confianza de que este sea el comportamiento de phpunit intencionado y consistente para confía en que eso ocurra.


A partir de PHPUnit 3.6, hay $this->returnValueMap() que puede usarse para devolver diferentes valores dependiendo de los parámetros dados al stub del método.


Lamentablemente, esto no es posible con la API PHPUnit Mock predeterminada.

Puedo ver dos opciones que pueden acercarte a algo como esto:

Usando -> at ($ x)

$context = $this->getMockBuilder(''Context'') ->getMock(); $context->expects($this->at(0)) ->method(''offsetGet'') ->with(''Matcher'') ->will($this->returnValue(new Matcher())); $context->expects($this->at(1)) ->method(''offsetGet'') ->with(''Logger'') ->will($this->returnValue(new Logger()));

Esto funcionará bien, pero está probando más de lo que debería (principalmente que se llama primero con el matcher, y ese es un detalle de implementación).

¡También esto fallará si tiene más de una llamada a cada una de las funciones!

Aceptar ambos parámetros y usar returnCallBack

Esto es más trabajo, pero funciona mejor ya que no depende del orden de las llamadas:

Ejemplo de trabajo:

<?php class FooTest extends PHPUnit_Framework_TestCase { public function testX() { $context = $this->getMockBuilder(''Context'') ->getMock(); $context->expects($this->exactly(2)) ->method(''offsetGet'') ->with($this->logicalOr( $this->equalTo(''Matcher''), $this->equalTo(''Logger'') )) ->will($this->returnCallback( function($param) { var_dump(func_get_args()); // The first arg will be Matcher or Logger // so something like "return new $param" should work here } )); $context->offsetGet("Matcher"); $context->offsetGet("Logger"); } } class Context { public function offsetGet() { echo "org"; } }

Esto dará como resultado:

/* $ phpunit footest.php PHPUnit 3.5.11 by Sebastian Bergmann. array(1) { [0]=> string(7) "Matcher" } array(1) { [0]=> string(6) "Logger" } . Time: 0 seconds, Memory: 3.00Mb OK (1 test, 1 assertion)

He usado $this->exactly(2) en el marcador para mostrar que esto también funciona al contar las invocaciones. Si no necesita que lo canjee por $this->any() , por supuesto, funcionará.