2010-03-22 22 views
9

Estoy compilando pruebas de unidad para la clase Foo, y soy bastante nuevo en las pruebas unitarias.PHPUnit: varios stubs de la misma clase

Un componente clave de mi clase es una instancia de BarCollection que contiene un número de objetos Bar. Un método en Foo itera a través de la colección y llama a un par de métodos en cada objeto Bar en la colección. Quiero usar objetos de código auxiliar para generar una serie de respuestas para mi clase de prueba. ¿Cómo hago para que la clase de stub Bar devuelva diferentes valores a medida que itero? Estoy tratando de hacer algo en este sentido:

$stubs = array(); 
foreach ($array as $value) { 
    $barStub = $this->getMock('Bar'); 
    $barStub->expects($this->any()) 
      ->method('GetValue') 
      ->will($this->returnValue($value)); 
    $stubs[] = $barStub; 
} 
// populate stubs into `Foo` 

// assert results from `Foo->someMethod()` 

Así Foo->someMethod() producirá datos en base a los resultados que recibe de los objetos Bar. Pero esto me da el siguiente error cada vez que la matriz es más que una:

There was 1 failure: 

1) testMyTest(FooTest) with data set #2 (array(0.5, 0.5)) 
Expectation failed for method name is equal to <string:GetValue> when invoked zero or more times. 
Mocked method does not exist. 
/usr/share/php/PHPUnit/Framework/MockObject/Mock.php(193) : eval()'d code:25 

Un pensamiento que tenía era utilizar ->will($this->returnCallback()) para invocar un método de devolución de llamada, pero no sé cómo indicar a la devolución de llamada, que Bar objeto está haciendo la llamada (y, en consecuencia, qué respuesta dar).

Otra idea es utilizar el método onConsecutiveCalls(), o algo así, para decirle a mi stub que regrese 1 la primera vez, 2 la segunda vez, etc., pero no estoy seguro de cómo hacerlo. También me preocupa que si mi clase hace algo diferente a la iteración ordenada en la colección, no tendré una manera de probarlo.

Respuesta

2

no estoy seguro de si por desgracia se puede resolver tu pregunta real utilizando getMock(), pero mi experiencia con getMock() sí es delgada.

Lo único que se me ocurre de improviso, pero sin saber su Bar clase, esto no puede ayudar: El tercer parámetro de getMock() permite pasar argumentos de constructor (como una matriz).

Crearía mi propia barra de extensión de clase falsa como ayudante de prueba (nombre de fantasía para "solo otra clase que solo se usa solo en pruebas") que hace exactamente lo que me gusta e inyecta una serie de ellas en su objeto Foo. Eso le da todo el control que desea, ya que puede reemplazar directamente los métodos en cuestión, que getMock() no hace. Por supuesto, eso también significa que no está probando la clase Bar en esta prueba, que puede no ser la que desea, aunque recomendaría escribir una clase de prueba por clase probada de todos modos, pero hay casos en que eso es innecesariamente purista .

$stubs = array(); 
foreach ($array as $value) { 
    $stubs[] = new MyBarTestHelper($value); 
} 

Dejando eso de lado, estoy sinceramente sorprendido de que solo vea la excepción que se describe cuando tiene más de un elemento de matriz.He observado que PHPUnit realmente espera que usted declare cualquier método que quiera que pueda rastrear como un parámetro getMock(), y de lo contrario se equivocará rotundamente, ya que esencialmente lo que hace internamente es crear su propia extensión del clase, ajustando cada método que declare expresamente con lógica que le permita determinar si se llamó (= agregando el nombre del método a una lista lógica).

Así color me ingenua (en serio, probablemente soy, yo soy un novato prueba, yo), pero a ver si esto le ayuda a cualquiera:

$stubs = array(); 
foreach ($array as $value) { 
    $barStub = $this->getMock('Bar', array('GetValue')); 
    $barStub->expects($this->any()) 
      ->method('GetValue') 
      ->will($this->returnValue($value)); 
    $stubs[] = $barStub; 
} 
+0

Crear mi propia clase de prueba era básicamente lo que tenía que hacer. En mi caso, pude usar la clase 'Bar' en sí, ya que los métodos que utilicé fueron simples getters, pero una clase simulada hecha a mano funcionaría con métodos más complejos. – keithjgrant

+0

Con respecto a la matriz de métodos válidos pasados ​​como el segundo parámetro a 'getMock()': Según la documentación, puede omitir este parámetro y se permitirá cualquier llamada al método. – keithjgrant

+0

Esa fue mi comprensión intuitiva, también, pero en realidad obtuve errores omitiendo que no mencioné expresamente los métodos llamados (por supuesto, solo en combinación con '-> espera()'); por lo tanto, mencionarlo. Sin embargo, lo que observé podría ser un error de versión muy específico de la versión. Pero, de cualquier forma, estoy muy contento de que hayas hecho que tu prueba funcione como se desea. :) – pinkgothic

0

Esto debería cumplir el requisito de devolver una serie de valores en orden como se llama si se siente cómodo con el uso de global. No tiene idea de qué barra se llama, pero si Foo llama una vez a cada barra una vez en orden, entonces no debería ser demasiado difícil completar los datos de prueba.

$barTestData = array('empty',1,2,3,4,5,6); 

function barDataCallback(){ 
    global $barTestData; 
    return next($barTestData); 
} 
0

Me di cuenta de que tiene un paréntesis adicional después de "-> method ('GetValue')" en su código. No sé si copió y pegó eso o no.

+0

ha corregido el error tipográfico, gracias. Esto no fue un copy-paste directo. Tengo algunas otras cosas sucediendo en mi código que habrían enlodado las aguas. – keithjgrant

+0

No puedo volver a crear su problema con el código que ha publicado. Creo que deberás publicar lo que estás haciendo realmente para obtener una buena respuesta. – Sean

+0

Interesante. Lo busqué un poco más, y no recibo el mismo mensaje de error que cité arriba. Me pregunto si eso fue el resultado de otro error que debo haber resuelto. Ahora mis pruebas parecen funcionar bien, pero fallan cuando deberían pasar. – keithjgrant

Cuestiones relacionadas