Inicio » Comunidad » Flaky test

Flaky test

1
0

Uno de los conceptos más desconocidos, pero a su vez más vividos, por los programadores es el «flaky test». Este concepto viene a referirse a la debilidad que tienen nuestros tests ya que son inestables y frágiles a cualquier cambio externo. Es decir, que el test se puede comportar diferente en cada ejecución presentando diferentes resultados (exitoso o fallido) sin haber realizado cambios en el código o en el test.

Imagina que tienes un caso de uso que matricula a un estudiante con un curso determinado.

class EnrollmentStudentUseCase
{
    private EnrollmentRepositoryInterface $enrollmentRepository;
    private CourseApi $courseApi;

    public function __construct(
        EnrollmentRepositoryInterface $enrollmentRepository,
        CourseApi $courseApi
    ) {
        $this->enrollmentRepository = $enrollmentRepository;
        $this->courseApi = $courseApi;
    }

    public function make(
        EnrollmentId $id,
        EnrollmentStudentId $studentId,
        EnrollmentCourseId $courseId
    ): void {
        $course = $this->courseApi->findByCourseId($courseId);

        $enrollment = Enrollment::make(
            $id,
            $studentId,
            $courseId,
            $course->title()
        );

        $this->enrollmentRepository->save($enrollment);
    }
}

Prueba unitaria

final class EnrollmentStudentUseCaseTest extends MockeryTestCase
{
    /** @test */
    public function it_should_enroll_student(): void
    {
        list($id, $title, $studentId, $courseId) = EnrollmentFaker::createValueObjectOne();
        $enrollmentRepositoryInterfaceMock = $this->createEnrollmentRepositoryInterfaceMock();
        $courseApi = new CourseApi();
        $enrollmentMaker = new EnrollmentStudentUseCase($enrollmentRepositoryInterfaceMock, $courseApi);

        $enrollmentMaker->make($id, $studentId, $courseId);
    }

    private function createEnrollmentRepositoryInterfaceMock(): EnrollmentRepositoryInterface
    {
        $mock = \Mockery::mock(EnrollmentRepositoryInterface::class);

        $mock->shouldReceive('save')->once()->withArgs([Enrollment::class])->andReturnNull();

        return $mock;
    }
}

El test depende de un servicio externo (CourseApi), si este servicio es bastante inestable el test fallará. Con lo cual, tendremos un flaky test. Una forma de resolver esto es mockeando la dependencia que tiene el caso de uso.

A continuación dejo una lista de cosas que pueden hacer que nuestro tests se conviertan en un flaky test.

  • Timeouts

  • Asynchronous Waits

  • Cache

  • Order dependency

  • Time of day

1
0

Me parece muy interesante este tema y es uno de los más difíciles de debugear.

Recientemente he tenido la «suerte» de tener flaky tests y a la lista de causas añadiría Random Variables.

En principio, no debería haber problema en nuestros tests si usamos variables con textos aleatorios, por ejemplo username o email, pero hay que llevar cuidado con utilizar random para asignar la ID en las entidades.

En el caso que menciono teníamos un id=rand(1, 100) por lo que una de cada 100 veces se creaban 2 entidades con la misma id y el test fallaba.

Otro punto importante que mencionas es el Order dependency. Es importante asegurarse que la suite de tests que se usa tenga habilitado la ejecución de los tests en orden aleatorio. (Por ejemplo: Phpunit no lo lleva activo por defecto) Hay que fijarse al inicio de los tests ya que si está activo aparece un mensaje indicando  Order seed: 12345. Este número será muy útil para obtener el mismo orden en caso de que los test fallen y poder localizar el error.

 

  • admin
    Sí, los datos son otro punto que pueden hacer que nuestros tests se conviertan en flaky tests. Sobre todo si utilizamos datos random, ahí debemos pensar que vamos a validar con esos datos.
1 resultado
Tu respuesta

Por favor, primero debes para enviar.

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos. Contiene enlaces a sitios web de terceros con políticas de privacidad ajenas que podrás aceptar o no cuando accedas a ellos. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Más información
Privacidad