Este foro ya no está activo, así que no puedes publicar nuevas preguntas ni responder a las preguntas existentes.

Simular el guardado de una entidad en PhpUnit

30 de diciembre de 2014

Hola, tengo una función para testear pero como soy nuevo en los test pues necesito ayuda. Como dice el titulo, ¿cómo podría testear el siguiente código para que simule que guarda o si hay alguna excepción a la hora de guardar?

public function preInscribir() {
    if(!$inscrito) {
        $inscrito = new Inscrito();
        $inscrito->setUsuario($this->usuario);
    }
 
    $inscrito->setFechaAlta(new \DateTime('now'));
 
    $this->entityManager->persist($inscrito);
    $this->entityManager->flush();
 
    return $inscrito;
}

Respuestas

#1

Aunque la pregunta es sencilla y directa, la respuesta no es tan sencilla porque hay que tener en cuenta muchas cosas. Vamos en centrarnos en la clave de tu pregunta: "¿cómo testear si hay alguna excepción a la hora de guardar?".

1. Lo primero que debes tener en cuenta es que no hay que testear lo que hace Doctrine (el persist() y el flush()). El motivo es que el propio Doctrine ya tiene varios miles de tests para comprobar que funciona bien. En otras palabras, si Doctrine está bien instalado y configurado, es seguro que sus funciones de guardado van a funcionar bien.

2. La parte más importante que debería probarse que es la información efectivamente se guarda en la base de datos. El problema es que esto nunca lo vas a poder probar bien en producción, que es donde realmente es importante probarlo. Si la base de datos de producción falla por cualquier motivo (y hay miles de motivos para que falle) jamás podrás detectarlo con un test unitario o funcional.

3. Lo que sí que puedes (y debes) probar es la funcionalidad que guarda información en la base de datos. Para ello, no se simula la inserción de información, sino que se inserta realmente y después se comprueba que se ha insertado. Si tu funcionalidad para crear información en la base de datos se accede por ejemplo mediante un método POST, puedes crear un test funcional como el siguiente:

public function testLaInformacionSeGuardaBien()
{
    $client = static::createClient();
    $client->request('POST', '/crear-informacion');
 
    $em = $client->getContainer()->getDoctrine()->getManager();
 
    // buscar por ID es cómodo, pero crea tests frágiles
    $entidad = $em->getRepository('AppBundle:Entidad')->find(1);
 
    // buscar por SLUG crea mejores tests
    $entidad = $em->getRepository('AppBundle:Entidad')->findBySlug('...');
 
    $this->assertEquals('Título de la entidad', $entidad->getTitle());
}

Para que los tests no creen problemas con la base de datos de producción, es esencial que configures una base de datos diferente en el archivo app/config/config_test.yml. Una buena práctica consiste en utilizar como nombre de la base de datos de prueba el mismo nombre que en producción/desarrollo pero con el sufijo _test.

@javiereguiluz

2 enero 2015, 22:24
#2

Hola Javier, me he estado leyendo un manualillo sobre esto, pero me entra alguna duda, ¿habría que testear una entidad por si sola? O sea por ejemplo:

Class Notificacion
{
    /**
     * @var integer
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;
 
    /**
     * @var string
     *
     * @ORM\Column(name="titulo", type="string", length=255)
     * @Assert\NotBlank()
     */
    private $titulo;
 
    /**
     * @var boolean
     *
     * @ORM\Column(name="estado", type="boolean")
     * @Assert\Type(type="bool")
     */
    private $estado = true;
 
   /**
     * @var \DateTime
     *
     * @ORM\Column(name="fechaPublicacion", type="date")
     * @Assert\NotBlank()
     * @Assert\Date()
     */
    private $fechaPublicacion;
 
    /**
     * Get id
     *
     * @return integer 
     */
    public function getId()
    {
        return $this->id;
    }
 
    /**
     * Set titulo
     *
     * @param string $titulo
     * @return Noticia
     */
    public function setTitulo($titulo)
    {
        $this->titulo = $titulo;
 
        return $this;
    }
 
    /**
     * Get titulo
     *
     * @return string 
     */
    public function getTitulo()
    {
        return $this->titulo;
    }
 
    /**
     * Set fechaPublicacion
     *
     * @param \DateTime  $fechaPublicacion
     * @return Temporada
     */
    public function setFechaPublicacion($fechaPublicacion)
    {
        $this->fechaPublicacion = $fechaPublicacion;
 
        return $this;
    }
 
    /**
     * Get fechaPublicacion
     *
     * @return \DateTime
     */
    public function getFechaPublicacion()
    {
        return $this->fechaPublicacion;
    }
}

@AlbertoVioque

14 enero 2015, 10:32
#3

@AlbertoVioque por poder sí que puedes, pero no le veo mucho sentido a hacer tests unitarios de entidades de Doctrine. Me parece que es bajar demasiado para probar cosas que seguramente no hace falta probar. Creo que es mejor hacer tests de mayor nivel y usar la entidad en esos tests para ver si se comporta como esperas.

@javiereguiluz

14 enero 2015, 10:58
#4

Muchas gracias, es que estoy intentando aprender TDD y me entran las dudas de hasta dónde hay que llegar. Aunque el manual que he leído usa otros lenguajes de programación .NET y Java, me cuesta ver la manera de empezar con los test cuando por ejemplo es una web de noticias, blog...

Veo que empieza con API antes de entrar con entidades y dice que es mejor dejar el tema de cómo va a ser el diseño para lo último. Pero claro, siempre he trabajado con diseño primero, ya que al fin y al cabo lo que suele ser es manipulación de datos, obtener y mostrar, poco más, y el estudio siempre lo he empezado por el diseño.

Supongo que es poco a poco jaja.

@AlbertoVioque

14 enero 2015, 16:30