tutorial español unit-testing api rest phpunit integration-testing

unit-testing - tutorial - manual postman español



¿Cómo se escriben las pruebas de integración para interactuar con API externa? (5)

¿Cómo pruebo la interacción con una API externa que afecta los datos en vivo?

Tu no Realmente debes confiar en que la API real realmente funciona.

Puedes, y debes, ejercitar la API con datos en tiempo real para asegurarte de que la entiendes.

Pero no es necesario que lo pruebes. Si la API no funciona, simplemente deja de usarla. No pruebe cada borde y caja de esquina.

¿Cómo puedo simular objetos en una prueba de Integración cuando están ocultos detrás de capas de abstracción?

Ese es el punto. Prueba la abstracción Debes confiar en que la implementación funciona. Estás probando tu código. No es su código.

¿Qué hago cuando falla una prueba y los datos en vivo se dejan en un estado inconsistente?

¿Qué? ¿Por qué estás probando API en vivo para asegurarte de que funcionan? Usted no confía en ellos? Si no confías en ellos, no lo pruebes. Encuentre un vendedor en quien pueda confiar.

Usted solo prueba su código. Confías en su código. Básicamente te burlas de su código para asegurarte de que tu código funcione.

Cómo haces esto.

  1. Juega con la API. Enviar solicitudes. Obtenga respuestas.

  2. Juega con tu aplicación. Averigüe qué tipo de solicitudes va a enviar.

  3. Regresa a la API. Envía una buena solicitud conocida. Obtenga la respuesta. Guarde esta respuesta . Esta es su respuesta estándar de oro a una buena solicitud. Canoniza esto en un caso de prueba.

  4. Ahora puede trabajar en su aplicación sabiendo que tiene una respuesta estándar de oro que realmente proviene de la API real. Eso debería ser suficiente para comenzar a manejar las respuestas.

  5. Después de haber trabajado en algunos casos de uso (solicitud correcta, solicitud incorrecta), debería poder obtener una buena respuesta y algunas respuestas de error típicas de la API. Guarde los buenos y los mensajes de error. Estos son útiles para las pruebas unitarias, para asegurarse de que está manejando algunos de los tipos de respuestas correctamente.

Primero, donde mi conocimiento está en:

Las pruebas unitarias son aquellas que prueban una pequeña porción de código (métodos únicos, principalmente).

Las pruebas de integración son aquellas que prueban la interacción entre múltiples áreas de código (que ojalá ya tengan sus propias pruebas unitarias). Algunas veces, partes del código bajo prueba requieren que otro código actúe de una manera particular. Aquí es donde entran en juego Mocks & Stubs. Por lo tanto, nos burlamos / rescindimos una parte del código para que se realice de manera muy específica. Esto permite que nuestra prueba de integración se ejecute de manera predecible sin efectos secundarios.

Todas las pruebas deben poder ejecutarse de manera independiente sin compartir datos. Si es necesario compartir datos, esto es una señal de que el sistema no está lo suficientemente desacoplado.

A continuación, la situación que estoy enfrentando:

Al interactuar con una API externa (específicamente, una API RESTful que modificará los datos en vivo con una solicitud POST), entiendo que podemos (¿debería?) Simular la interacción con esa API (más elocuentemente indicada en esta respuesta ) para una prueba de integración . También entiendo que podemos probar los componentes individuales de la interacción con esa API (construir la solicitud, analizar el resultado, arrojar errores, etc.). Lo que no entiendo es cómo hacerlo.

Entonces, finalmente: Mi pregunta (s).

¿Cómo pruebo mi interacción con una API externa que tiene efectos secundarios?

Un ejemplo perfecto es la API de contenido de Google para comprar . Para poder realizar la tarea en cuestión, se requiere una cantidad decente de trabajo de preparación, luego realizar la solicitud real y luego analizar el valor de retorno. Algo de esto es sin un entorno de ''caja de arena'' .

El código para hacer esto generalmente tiene bastantes capas de abstracción, algo así como:

<?php class Request { public function setUrl(..){ /* ... */ } public function setData(..){ /* ... */ } public function setHeaders(..){ /* ... */ } public function execute(..){ // Do some CURL request or some-such } public function wasSuccessful(){ // some test to see if the CURL request was successful } } class GoogleAPIRequest { private $request; abstract protected function getUrl(); abstract protected function getData(); public function __construct() { $this->request = new Request(); $this->request->setUrl($this->getUrl()); $this->request->setData($this->getData()); $this->request->setHeaders($this->getHeaders()); } public function doRequest() { $this->request->execute(); } public function wasSuccessful() { return ($this->request->wasSuccessful() && $this->parseResult()); } private function parseResult() { // return false when result can''t be parsed } protected function getHeaders() { // return some GoogleAPI specific headers } } class CreateSubAccountRequest extends GoogleAPIRequest { private $dataObject; public function __construct($dataObject) { parent::__construct(); $this->dataObject = $dataObject; } protected function getUrl() { return "http://..."; } protected function getData() { return $this->dataObject->getSomeValue(); } } class aTest { public function testTheRequest() { $dataObject = getSomeDataObject(..); $request = new CreateSubAccountRequest($dataObject); $request->doRequest(); $this->assertTrue($request->wasSuccessful()); } } ?>

Nota: Este es un ejemplo de PHP5 / PHPUnit

Dado que testTheRequest es el método llamado por el conjunto de pruebas, el ejemplo ejecutará una solicitud en vivo.

Ahora, esta solicitud en vivo (con suerte, siempre que todo haya ido bien) haga una solicitud POST que tenga el efecto secundario de alterar datos en vivo.

¿Es esto aceptable? ¿Qué alternativas tengo? No veo una manera de burlar el objeto Solicitud para la prueba. E incluso si lo hiciera, significaría configurar los resultados / puntos de entrada para cada ruta de código posible que acepte la API de Google (que en este caso debería encontrarse por prueba y error), pero me permitiría el uso de dispositivos.

Otra extensión es cuando ciertas solicitudes se basan en ciertos datos que ya están en vivo. Utilizando de nuevo la API de contenido de Google como ejemplo, para agregar un suministro de datos a una cuenta secundaria, la cuenta secundaria ya debe existir.

Un enfoque en el que puedo pensar son los siguientes pasos;

  1. En testCreateAccount
    1. Crear una subcuenta
    2. Assert la sub-cuenta fue creada
    3. Eliminar la subcuenta
  2. Haga que testCreateDataFeed dependa de que testCreateAccount no tenga ningún error
    1. En testCreateDataFeed , crea una nueva cuenta
    2. Crea el feed de datos
    3. Assert the data feed fue creado
    4. Eliminar la fuente de datos
    5. Eliminar la subcuenta

Esto luego plantea la pregunta adicional; ¿Cómo pruebo la eliminación de feeds de datos / cuentas? testCreateDataFeed parece sucio: ¿qué testCreateDataFeed si falla la creación de la fuente de datos? La prueba falla, por lo tanto, la subcuenta nunca se elimina ... No puedo probar la eliminación sin creación, así que escribo otra prueba ( testDeleteAccount ) que se basa en testCreateAccount antes de crear y luego eliminar una cuenta propia (ya que los datos no deberían no se comparte entre las pruebas).

En resumen

  • ¿Cómo pruebo la interacción con una API externa que afecta los datos en vivo?
  • ¿Cómo puedo simular objetos en una prueba de Integración cuando están ocultos detrás de capas de abstracción?
  • ¿Qué hago cuando falla una prueba y los datos en vivo se dejan en un estado inconsistente?
  • ¿Cómo en código realmente hago todo esto?

Relacionado:


Esta es más una respuesta adicional a la ya dada :

Mirando a través de su código, la class GoogleAPIRequest tiene una dependencia codificada de class Request . Esto evita que lo pruebe independientemente de la clase de solicitud, por lo que no puede simular la solicitud.

Debe hacer la solicitud inyectable, para que pueda cambiarla a una prueba simulada mientras realiza la prueba. Hecho esto, no se envían solicitudes HTTP API reales, los datos en vivo no se modifican y puede realizar la prueba mucho más rápido.


Recientemente tuve que actualizar una biblioteca porque la API a la que se conectó se actualizó.

Mi conocimiento no es suficiente para explicar en detalle, pero aprendí mucho al mirar el código. https://github.com/gridiron-guru/FantasyDataAPI

Puede enviar una solicitud como lo haría normalmente a la API y luego guardar esa respuesta como un archivo json, luego puede usar eso como un simulacro.

Eche un vistazo a las pruebas en esta biblioteca que se conecta a una API usando Guzzle.

Se burla de las respuestas de la API, hay una gran cantidad de información en los documentos sobre cómo funciona la prueba que podría darte una idea de cómo hacerlo.

pero básicamente haces una llamada manual a la API junto con los parámetros que necesitas, y guardas la respuesta como un archivo json.

Cuando escribe su prueba para la llamada de API, envíe los mismos parámetros y haga que se cargue en el simulacro en lugar de usar la API en vivo, luego puede probar los datos en el simulacro que creó que contiene los valores esperados.

Mi versión actualizada de la API en cuestión se puede encontrar aquí. Repo actualizado


Sobre la base de lo que dice la respuesta más votiva ... Así es como lo he hecho y funciona muy bien.

  1. Creado un objeto de rizo simulado
  2. Dile a la burla qué parámetros esperaría
  3. Imagina cuál será la respuesta de la llamada curl dentro de tu función
  4. Deja que tu código lo haga

    $curlMock = $this->getMockBuilder(''/Curl/Curl'') ->setMethods([''get'']) ->getMock(); $curlMock ->expects($this->once()) ->method(''get'') ->with($URL . ''/users/'' . urlencode($userId)); $rawResponse = <<<EOL { "success": true, "result": { .... } } EOL; $curlMock->rawResponse = $rawResponse; $curlMock->error = null; $apiService->curl = $curlMock; // call the function that inherently consumes the API via curl $result = $apiService->getUser($userId); $this->assertTrue($result);


Una de las formas de probar API externas es la que mencionaste al crear un simulacro y trabajar en contra de eso con el comportamiento codificado como lo has entendido.

A veces las personas se refieren a este tipo de pruebas como pruebas "basadas en contratos", donde puedes escribir pruebas contra la API en función del comportamiento que has observado y codificado, y cuando esas pruebas comienzan a fallar, el "contrato se rompe". Si son simples pruebas basadas en REST que usan datos ficticios, también puede proporcionarlas al proveedor externo para que puedan descubrir dónde / cuándo podrían estar cambiando la API lo suficiente como para que sea una nueva versión o producir una advertencia sobre no retroceder. compatible.

Ref: https://www.thoughtworks.com/radar/techniques/consumer-driven-contract-testing