test - PHPUnit: Haciendo aserciones en variables no públicas
que es phpunit (4)
Estoy de acuerdo con los demás en que, en general, desea evitar el acceso privado a sus pruebas, pero para los casos en que lo necesite, puede usar la reflexión para leer y escribir la propiedad .
Supongamos que tengo una clase con una propiedad privada y un captador y definidor público asociado. Quiero probar con PHPUnit que la propiedad obtiene el valor correcto después de que se haya utilizado el establecedor o que el que obtiene devuelva la propiedad correcta.
Por supuesto, puedo probar el setter usando el getter para ver que el objeto está almacenando el valor correcto, y viceversa para probar el getter. Sin embargo, esto no garantiza que la propiedad privada sea la que se establece.
Digamos que tuve la siguiente clase. He creado una propiedad, getter y setter. Pero hice un error tipográfico en el nombre de la propiedad, por lo que el getter y el setter realmente no manipulan la propiedad que deben manipular
class SomeClass
{
private
$mane = NULL; // Was supposed to be $name but got fat-fingered!
public function getName ()
{
return ($this -> name);
}
public function setName ($newName)
{
$this -> name = $newName;
return ($this);
}
}
Si ejecuto la siguiente prueba
public function testSetName ()
{
$this -> object -> setName (''Gerald'');
$this -> assertTrue ($this -> object -> getName () == ''Gerald'');
}
Yo obtendría un pase. Sin embargo, algo muy malo realmente ha sucedido que no quiero. Cuando se llama a setName (), en realidad crea una nueva propiedad en la clase con el nombre que pensé que tenía mi propiedad privada, ¡solo la que crea el establecedor es pública! Puedo demostrar eso con el siguiente código:
$a = new SomeClass;
$a -> setName(''gerald'');
var_dump ($a -> getName ());
var_dump ($a -> name);
Sería de salida:
cuerda (6) "gerald"
cuerda (6) "gerald"
¿Hay alguna forma de acceder a las propiedades privadas desde PHPUnit para poder escribir pruebas que me aseguren de que las propiedades que creo que se están obteniendo y configurando realmente se están obteniendo y configurando?
¿O hay alguna otra cosa que debería hacer en una prueba para detectar problemas como este sin intentar acceder al estado privado del objeto bajo prueba?
Para las propiedades de prueba, haría los mismos argumentos que formuló luego hablando de probar métodos privados.
You usually don''t want to do this
.
Se trata de probar el comportamiento observable.
Si cambia el nombre de todas sus propiedades o decide almacenarlas en una matriz, no debería necesitar adaptar sus pruebas. ¡Quieres que tus pruebas te digan que todo sigue funcionando ! Cuando necesita cambiar las pruebas para asegurarse de que todo sigue funcionando, pierde todos los beneficios, ya que también podría cometer un error al cambiar las pruebas.
Entonces, en general, ¡pierde el valor de su suite de pruebas!
Solo probar las combinaciones de obtener / establecer estaría bien, pero por lo general no todos los creadores deberían tener un captador y crearlas para probarlas no es algo agradable, éter.
Por lo general, establece algunas cosas y luego le dice al método que DO
(comportamiento) algo. Probar eso (que la clase haga lo que debe hacer) es la mejor opción para probar y debería hacer que las propiedades sean superfluas.
Si realmente quieres hacer eso, existe la funcionalidad setAccessible
en la API de reflexiones de PHP pero no puedo crear un ejemplo en el que encuentre esto deseable.
Encontrar propiedades no utilizadas para detectar errores / problemas como este:
El detector de UnusedPrivateField Rule
PHP como una UnusedPrivateField Rule
class Something
{
private static $FOO = 2; // Unused
private $i = 5; // Unused
private $j = 6;
public function addOne()
{
return $this->j++;
}
}
Esto generará dos advertencias para usted porque nunca se accede a las variables
Solo quiero señalar una cosa. Olvidémonos de los campos privados por un momento y concentrémonos en lo que le importa al cliente de su clase. Su clase expone un contrato, en este caso, la capacidad de alterar y recuperar el nombre (a través de getter y setter). La funcionalidad esperada es simple:
- cuando establezco el nombre con
setName
en"Gerald"
, espero obtener"Gerald"
cuando llamogetName
Eso es todo. El cliente no (bueno, ¡no debería!) Preocuparse por la implementación interna. Si usó un nombre de campo privado, hashset o servicio web llamado a través de un código generado dinámicamente, no importa para el cliente. El error que está experimentando actualmente, desde el punto de vista del usuario, no es un error en absoluto.
Si PHPUnit le permite probar variables privadas, no lo sé. Pero desde la perspectiva de la prueba de unidad, no deberías hacer eso.
Editar (en respuesta al comentario):
Entiendo sus preocupaciones sobre la posible exposición del estado interno, sin embargo, no creo que las pruebas unitarias sean la herramienta correcta para lidiar con eso. Puede idear muchos escenarios posibles de cómo algo podría hacer otra cosa que no se planeó. Las pruebas unitarias no son de ninguna manera cura para todos y no deben usarse como tales.
También puede usar Assert::assertAttributeEquals(''value'', ''propertyName'', $object)
.
Consulte https://github.com/sebastianbergmann/phpunit/blob/3.7/PHPUnit/Framework/Assert.php#L490