2012-02-28 9 views
13

En PHPUnit podemos especificar el método fue llamado con especialComprobar que el método de simulacro se llama sin ningún tipo de parámetros pasados ​​(en PHPUnit)

->with($this->equalTo('foobar')) 

o cualquier parámetro

->with($this->anything()) 

.

¿Pero hay una forma de especificar que el método ha sido llamado sin parámetros?

Esta es la prueba que espero a fallar:

public function testZ() 
{ 
    $a = $this->getMock('q'); 

    $a->expects($this->once()) 
     ->method('z') 
     ->with(); // <--- what constraint to specify here? 

    $a->z(1); 
} 

UPD:

La pregunta tiene carácter teórico, así que no tengo ningún ejemplo de la vida real. Algunos casos, podría ser útil que se me ocurre en este momento es:

public function testMe($object) 
{ 
    $object->foo(); 
} 

Y vamos a suponer que debería testMe (por diseño y por los requisitos) siempre llamar al método sin parámetros (suponiendo foo() tiene falta de pago). Porque cualquier parámetro no predeterminado (más preciso: cualquier parámetro! = Al predeterminado uno, que aún no conocemos y que probablemente podría cambiar de forma independiente) en este caso causa consecuencias fatales.

+0

+1 He pasado unos minutos buscando en el origen de PHPUnit en github y parece que '-> con()' solo funciona para realmente especificar parámetros, no prohibirlos. Realmente no puedo pensar en un escenario donde verificar que no se pasó ningún argumento es algo que necesitarías verificar, ¿no? Me interesaría saber por qué necesita verificar que no se envió ningún argumento. Pasar un argumento cuando no se espera ninguno, no romperá nada y ¿no puede simplemente pasar un NULO cuando se espera un argumento que no se puede proporcionar? – rdlowrey

+0

@rdlowrey: se agregó una actualización de la explicación ;-) – zerkms

+0

@rdlowrey: 'no se puede pasar un NULL cuando se espera un argumento que no se puede proporcionar --- --- no no se puede. El método todavía podría tener parámetros opcionales – zerkms

Respuesta

6

Mientras que rdlowrey tiene razón en que with() no toma medidas para verificar que no se hayan pasado los argumentos, el problema no está en PHPUnit sino en PHP.

Primero, si su método no proporciona los valores predeterminados, el intérprete generará un error fatal si no pasa ningún parámetro. Esto es algo esperado y no del todo relevante para la pregunta en cuestión, pero es importante declarar desde el principio.

Segundo, si su método hace proporciona valores predeterminados, llamar al método sin argumentos hará que PHP modifique la llamada antes de que PHPUnit se involucre para pasar los valores predeterminados en su lugar. Aquí hay una prueba simple que demuestra que PHP se inserta antes de que PHP pueda verificar los parámetros. Es clave darse cuenta de que la clase falsa que crea PHP tiene la misma firma que la clase burlada, incluidos los valores predeterminados.

class MockTest extends PHPUnit_Framework_TestCase { 
     public function test() { 
       $mock = $this->getMock('Foo', array('bar')); 
       $mock->expects($this->once()) 
        ->method('bar') 
        ->with() // does nothing, but it doesn't matter 
        ->will($this->returnArgument(0)); 
       self::assertEquals('foobar', $mock->bar()); // PHP inserts 1 and 2 
       // assertion fails because 1 != 'foobar' 
     } 
} 

class Foo { 
     public function bar($x = 1, $y = 2) { 
       return $x + $y; 
     } 
} 

Esto significa que puede verificar que sea nada se pasa o se hicieron pasar a los valores por defecto, pero no puedes ser más específico.

¿Puede evitar esta limitación? Puede eliminar los valores predeterminados de los argumentos al anular los métodos, por lo que debería poder crear una subclase y simularla. ¿Vale la pena? Mi reacción instintiva inicial es que este es un gran olor a código. O su diseño o sus pruebas están haciendo lo incorrecto (tm).

Si puede proporcionar un ejemplo real del mundo real en el que realmente necesita hacer este tipo de prueba, vale la pena dedicar algo de tiempo a reflexionar sobre una solución. Hasta entonces, estoy satisfecho con la respuesta puramente académica de "no hagas eso". :)

+0

+1 para la aclaración. Estoy de acuerdo en que parece que el código huele ... No he visto una aplicación en el mundo real y parece un problema que una simple refactorización evitaría. – rdlowrey

+0

"Hasta entonces, estoy satisfecho con la respuesta puramente académica de" no hagas eso ". :)" --- Estoy de acuerdo en que no puedo pensar en el ejemplo del mundo real y es por eso que dije "La pregunta tiene naturaleza teórica "- así que solo pregunté sobre la posibilidad teórica de hacerlo sin explicaciones por qué lo necesito ;-) – zerkms

+0

Pero aún me pregunto cómo se burla de eso – zerkms

4

Los objetos de simulación PHPUnit solo pueden usar el método de restricción ->with() para verificar que el recuento o los valores pasados ​​de los parámetros coinciden con los que se pasaron al método simulado cuando se invocaron. No puede usarlo para requerir que sin argumentos se pasen al método de prueba.

El proceso de verificación simulada comprueba específicamente que el recuento de parámetros pasados ​​y los valores asociados son compatibles con los pasados ​​a la restricción with. Además, como probablemente haya visto, la especificación de la restricción with sin ningún valor tampoco funcionará; si with no recibe parámetros, no agregará ninguna restricción de parámetros para la verificación.

Puede ver el método real PHPUnit_Framework_MockObject_Matcher_Parameters::verify utilizado para verificar los parámetros del método simulado en la fuente vinculada de github.

Si la validación de los argumentos no pasados ​​es un requisito, deberá especificar su propia clase simulada para verificar dicha condición fuera de las capacidades de simulación PHPUnit.

+0

Sin editar esta respuesta, quiero agregar que he llegado a esta conclusión no desde una comprensión increíblemente matizada de las partes internas de PHPUnit, sino desde hace mucho tiempo la búsqueda del código fuente relevante en un intento de lograr el objetivo declarado de la pregunta. Creo que el código fuente vinculado es una prueba de que no es posible, pero si alguien puede encontrar la manera de hacerlo funcionar, por favor compártelo. – rdlowrey

Cuestiones relacionadas