Este artículo es parte de una serie en la que documente las ideas, los cambios y el replanteamiento que experimenté al refactorizar la base de código para Pulse , una herramienta de monitoreo de sitios y servidores indolora y asequible diseñada para desarrolladores.
Hoy, me gustaría hablar sobre cómo creé clases falsas para probar la funcionalidad que depende de hacer solicitudes a través de Internet. Vamos a profundizar en…
¿Por qué crear clases falsas?
En términos generales, si puede evitar crear una clase falsa, le recomendaría absolutamente que lo haga. Es el mismo argumento que existe para ser cauteloso sobre el uso
mocks
y spies
en su código ... realmente no está probando su código, sino probando la sintaxis / interacción de su código.De acuerdo, si es así, ¿por qué querría usarlos?
La respuesta a eso es simple. Rendimiento . Considere el siguiente ejemplo, escribe una prueba que realiza una solicitud HTTP a un tercero, por ejemplo, acme.com. Recibe la respuesta y su código reacciona en consecuencia.
Bien y elegante ... pero ¿y si la respuesta no fuera la que esperabas? ¿Y si el sitio fuera lento? ¿Qué pasa si el sitio estaba fuera de línea? ¿Qué pasa si su conexión a Internet no funcionaba correctamente?
Incluso si pudo mitigar esos problemas cada vez que ejecutó la prueba, todavía hay una cosa que no puede abordar y es la latencia involucrada en el envío de la solicitud HTTP. Su prueba tiene que esperar la respuesta.
En el caso de una sola prueba, no es un gran problema, pero imagine si su conjunto de pruebas tenía cientos o incluso miles de pruebas que involucraban solicitudes HTTP. No desea estar en una posición en la que se tarde una hora en ejecutar su conjunto de pruebas.
Clases falsas al rescate
La manera fácil de resolver este problema es envolver la funcionalidad que envía una solicitud HTTP dentro de una clase. Luego, dentro de su aplicación, resuelve esta clase fuera del contenedor de servicios de Laravel y llama a sus métodos.
Para sus pruebas, crea una clase separada que hereda de esta clase principal. Luego anula los métodos para realizar la misma funcionalidad pero sin enviar realmente la solicitud HTTP.
Finalmente, dentro de sus pruebas, instruye al contenedor de servicios de Laravel a
swap
la clase principal con su clase falsa. De esa manera, cuando su aplicación solicita una instancia de la clase principal, obtiene la clase falsa en su lugar.
Si eres nuevo en esto, puede ser un poco abrumador, así que simplifiquemos las cosas mirando un ejemplo de Pulse.
Enviar una solicitud HTTP
Como parte de sus actividades de monitoreo, Pulse realiza una solicitud HTTP al sitio de un usuario y verifica el código de estado HTTP que recibe. Para hacer esto, la aplicación llama al
getStatusCode
método en una clase llamada PingSite
.
Aquí hay un ejemplo simplificado de la clase:
class PingSite { / ** * Envía una solicitud HTTP a una url y recupera su código de estado. * * / public function getStatusCode (string $ url): int { return $ client-> request ($ url) -> statusCode; } }
Luego, dentro de la aplicación, en lugar de simplemente crear una nueva instancia de la
PingSite
clase, sacamos resolve
la clase del contenedor de servicios:// NO $ ping = new PingSite (); // SÍ $ ping = resolve (PingSite :: class);
Aparte de cómo instanciamos la
PingSite
clase, todo sigue igual. Todavía devuelve un objeto de tipo PingSite
.Crear la implementación falsa
Para nuestras pruebas, necesitamos crear una clase falsa que anule el
getStatusCode
método y en su lugar simplemente devuelva un número entero. Sin embargo, necesitamos una forma de establecer el número entero que se devuelve para que podamos probar una variedad de escenarios.
Agreguemos una propiedad a nuestra clase falsa y establezcamos su valor en el constructor. Luego podemos modificar el
getStatusCode
método para devolver el valor de la propiedad:la clase PingSiteFake extiende PingSite { código $ protegido; función pública __construct (int $ code) { $ this-> code = $ code; } / ** * Simular una solicitud HTTP a una url y obtener su código de estado. * * / public function getStatusCode (string $ url): int { return $ this-> code; } }
Finalmente, todo lo que tenemos que hacer dentro de nuestras pruebas es instruir a Laravel para que use nuestra clase falsa al resolver
PingSite
desde el contenedor de servicios:/ ** @test * / public function it_can_ping_a_url_and_get_the_http_status_code () { // Usa la implementación falsa $ this-> swap (PingSite :: class, new PingSiteFake (201)); $ this-> get ('/ ping / google.com') -> afirmarJson (['estado' => 201]); }
Y eso es todo lo que hay que hacer. Esta prueba ahora se ejecutará en un par de milisegundos, en lugar de un segundo o más si realmente enviamos una solicitud HTTP genuina.
Advertencias a tener en cuenta
Como se mencionó al principio, el argumento sobre tener cuidado con este enfoque todavía se aplica. Como probablemente se dio cuenta, no estamos realmente probando
PingSite
, estamos vez probar el código que interactúa con PingSite
.
Todavía es increíblemente importante escribir pruebas que realmente utilicen
PingSite
y no su implementación falsa, para garantizar que funcione correctamente. Sin embargo, en lugar de escribir docenas, cientos o incluso miles de pruebas que son lentas porque todas se usan PingSite
, solo necesita escribir un puñado que pruebe específicamente la funcionalidad de la PingSite
clase.
Esto asegurará que su conjunto de pruebas se ejecute significativamente más rápido.
Terminando
Esperemos que haya visto cómo el uso de clases falsas puede ser significativamente beneficioso para mejorar el rendimiento de su conjunto de pruebas. Tengo más artículos para compartir, así que si estás interesado en leerlos, asegúrate de seguirme aquí en Medium. También puedes seguirme en Twitter .
Por último, si está buscando una herramienta de monitoreo de sitios y servidores asequible e indolora que no requiera que tenga un título de DevOps, tómese un momento para consultar Pulse . ¡Creo que lo encontrarás como un soplo de aire fresco!
0 Comentarios