¿Cómo se prueba una función cuyo único propósito es consultar una API externa, pero la API utiliza una sintaxis de consulta compleja?

16

La única lógica real está en la sintaxis de consulta para la API externa. No quiero probar si consulta la API, quiero comprobar que la consulta de tal manera que se devuelvan los datos correctos. Por ejemplo, algunos pseudocódigo:

function retrieve_related_data(id)
{
  query = "[potentially long, syntactically complex query that
            uses param id to get some data]";
  results = api_wrapper.query(query);
  return results;
}

Un ejemplo más concreto con una API inventada:

function retrieveLifeSupportingObjectsWithinRegion(id)
{
  query = "
    within region(" + id + ") as r
    find objects matching hydration>0 and temp_range has 75
    send name, id, relative(position, r)        
  ";
  results = astronomicalObjectApiWrapper.query(query);
  return results;
}

La consulta está en una sintaxis personalizada para la API y es compleja y hay varias formas de lograr los mismos resultados o resultados similares. El propósito de la función no es obtener datos identificados por, idsino encontrar un subconjunto de otros datos basados ​​en una relación difusa con los datos identificados por ideso que también cumple con algunos otros requisitos. Los otros requisitos son siempre los mismos independientemente de, idpero pueden cambiar con el tiempo a medida que se modifica el sistema. Por ejemplo, si la API de ejemplo agrega soporte para información de gravedad, es posible que queramos cambiar la consulta para usar también la gravedad para refinar los resultados. O tal vez se nos ocurra una forma más eficiente de verificar el rango de temperatura, pero no cambia los resultados.

Lo que quiero probar es que para una entrada dada idse devuelve el conjunto correcto de datos. Quiero probar esto para que si alguien desordena la consulta de modo que ya no devuelva los datos correctos en función de idque fallará, pero también quiero que las personas puedan modificar la consulta para refinarla sin necesidad de modificar también la prueba.

Opciones que he considerado:

  1. Podría tropezar la API, pero eso sería demasiado simple (verifique que idesté presente en la consulta y luego devuelva un conjunto de datos esperado si es así o un conjunto inesperado si no), demasiado frágil (verifique que la cadena de consulta sea exactamente lo que está en la función), o demasiado complejo (verifique que la consulta utilizada sea sintácticamente correcta y dará como resultado la devolución de los datos correctos).

  2. Podría enviar la consulta a la API real, pero los resultados esperados podrían cambiar con el tiempo a medida que cambien los datos en el sistema externo, fuera del control del sistema de prueba.

  3. Podría considerar configurar una instalación de prueba de la API real para controlar los datos que tiene, pero eso es un gran esfuerzo.

Me estoy inclinando hacia el n. ° 2 y estoy haciendo esto más como una prueba de integración que no se ejecuta con frecuencia y viendo con qué frecuencia los cambios en los datos del sistema externo hacen que la prueba se rompa. Creo que eso sería más simple por ahora, pero me pregunto si hay alternativas en las que no estoy pensando o mejores formas de abordar este problema. Cualquier consejo sería apreciado.

Joshua Coady
fuente
Estaba pensando en esto como una prueba de unidad, pero ¿tal vez es realmente una prueba de integración o una prueba de aceptación de bajo nivel?
Joshua Coady
2
¿Es una API de solo lectura? ¿O puede escribir datos con los que pueda verificar de manera confiable sus lecturas ?
svidgen 01 de
¿Es esta pregunta diferente de "cómo probar que mi sql (= sintaxis compleja) devuelve los datos correctos"? Con bases de datos por lo general tienen algunas pruebas de integración que prueba la porquería-sql-sintaxis y un repositorio de Fasade burlado para verificar BusinessLogic
k3b

Respuestas:

7

Puede parecer que validar la respuesta API externa estaríamos probando nuestra función, pero no sería totalmente cierto. De alguna manera, estaríamos probando la API externa y el entorno en el que se ejecuta la API.

Nuestras pruebas deben abordarse para garantizar el comportamiento esperado del código que hemos escrito, no el escrito por terceros.

Hasta cierto punto, tenemos que confiar en la función adecuada de las API y las bibliotecas en las que confiamos. Por ejemplo, generalmente no probamos los componentes del marco que implementamos.

¿Por qué lo digo yo?

Lo que quiero probar es que para un id de entrada dado se devuelve el conjunto correcto de datos

¿Qué se probaría aquí? Como dijiste, los datos y su corrección no están bajo nuestro control, por lo que estaríamos restringiendo el éxito de la fase de prueba a un agente externo que no tenemos ningún control. Estas pruebas son candidatas para volverse no deterministas y definitivamente, no queremos este tipo de pruebas en nuestra cartera de proyectos .

Una preocupación diferente es validar el contrato. Me resultaría bastante útil probar un contrato 1 para garantizar que la integración siga funcionando como se esperaba, antes de cualquier lanzamiento o implementación.

Quiero probar esto para que si alguien desordena la consulta de modo que ya no devuelva los datos correctos basados ​​en la identificación, que fallará

¿Qué sucede si la consulta está bien, pero los datos son incorrectos debido a errores en la API? No solo los datos están fuera de nuestro control. La lógica también lo es.

La implementación de pruebas funcionales o pruebas de extremo a extremo puede ayudar aquí. Puede abordar estas pruebas para validar ciertas rutas de ejecución de modo que si las API devuelven datos incorrectos, esto probablemente causará comportamientos y resultados inesperados. Por otro lado, esperaría que la API arroje errores si mis consultas tienen un formato incorrecto.

Pero también quiero que las personas puedan modificar la consulta para refinarla sin necesidad de modificar también la prueba.

Sugiero implementar una herramienta para tal propósito. Podría ser tan simple como:

  • Una clase que se ejecuta como prueba pero no pertenece al plan de prueba.
  • Un script de shell + rizo

O algo más sofisticado. Por ejemplo, un cliente independiente.

En cualquier caso, la función bajo la pregunta, bien vale dos tipos de pruebas:

  • Prueba de unidad. Como dijiste, tienes que bloquear la API externa, pero ese es el propósito de las pruebas unitarias. Probar nuestro código aislando las dependencias.

  • Examen de integración. Verifique que el código no solo envíe la solicitud correcta, sino que maneje adecuadamente el contenido de respuesta, errores, redireccionamientos, etc. Realice pruebas para todos estos casos, pero no pruebe datos .

Nota al margen: su pregunta es similar a -como prueba las declaraciones SQL de la aplicación-?

Preguntas relacionadas :


1: Quizás te interese la respuesta de @ DocBrown sobre este tema

Laiv
fuente
"El problema (IMO) es que estás demasiado concentrado en probar la API externa". - No veo nada que indique que el autor de la pregunta esté interesado en probar la API externa. Además, usted dice "bloquear la API externa", pero ¿tiene alguna sugerencia sobre si el autor de la pregunta debe usar la opción "demasiado simple", la opción "demasiado frágil", la opción "demasiado compleja" o alguna cuarta opción?
Tanner Swett
La pregunta OP es preguntar cómo probar una función que llama a una API externa. Pero al leer sus dudas, me parece que él pone demasiado énfasis en probar la consulta y sus resultados. Hice 4 sugerencias: (1) no hagas una prueba de la API. (2) no use las pruebas de integración como banco de trabajo para ajustar la consulta. Haz una herramienta en su lugar. (3) volviendo a la pregunta principal, haga su prueba unitaria y de integración. Pero no valida el contenido de la respuesta API. (4) Pregunte al gerente del proyecto si deberían / ​​pueden hacer un conjunto de pruebas de la API externa como parte del plan de prueba del proyecto.
Laiv
1
Considero la consulta en sí misma como "código escrito por nosotros". El objetivo final son las pruebas automatizadas para alertarnos si introdujimos un error en nuestro código. Supongo que es similar a eso: creo que es similar a eso: creo que mi pregunta es cómo prueba que su código está consultando una API externa de manera que la API responda según lo previsto (suponiendo que respuesta nominal). Creo que lo que está diciendo es dejar eso fuera de la unidad y las pruebas de integración, pero si las consultas son de misión crítica, podríamos configurar algunas otras pruebas automatizadas por separado para probar la API externa en vivo.
Joshua Coady
1
En mi opinión, la mejor manera es hacer una prueba funcional, el cambio en la cláusula where que nunca será cierta, causará un comportamiento diferente en una o más de mis pruebas funcionales. UT son solo una pequeña pieza en el plan de prueba.
Laiv
2
Gracias por ser una caja de resonancia. Supongo que, en última instancia, aunque la consulta tiene una lógica personalizada, está fuera del dominio de las pruebas unitarias porque la consulta es un código que se "ejecuta" fuera del sistema que se está probando. Solo necesitaba que alguien me dijera eso varias veces de diferentes maneras antes de verlo;)
Joshua Coady
2

He visto comprobaciones de unidades que comprueban que la cadena de consulta generada coincide con un valor esperado.

Sin embargo. Esto fue en mi opinión si uso limitado. La sintaxis de la consulta era complicada, posiblemente con errores, por lo que A tenía infinitas posibilidades de verificar y B, incluso si la cadena se generaba "correctamente", se podían devolver resultados inesperados en el entorno en vivo.

Creo que tiene razón al elegir su opción 2. ejecutar pruebas de integración contra la instancia en vivo.

Siempre y cuando no sean destructivos, estas son las primeras pruebas que debe escribir, ya que detectarán, aunque no identificarán la causa de ningún error.

La opción 3 'desplegar una instancia de prueba con datos ficticios' es superior. Pero no afecta su escritura de prueba, ya que puede apuntar las mismas pruebas al servidor de prueba si se convierte en un buen uso del tiempo para implementar una.

Ewan
fuente
0

Depende de la API, pero si es posible, vaya a la opción # 3 (instancia de prueba privada).

Rebajar la API (opción n. ° 1) es la peor opción, debido a las razones que mencionó, y seguir esta ruta probablemente hará más daño que bien (mucho tiempo perdido).

Correr contra la API real (opción # 2) hace que las pruebas sean escamosas y poco confiables, y después de algunos falsos positivos, la gente simplemente dejará de usarlas. No solo pueden cambiar los datos, sino que el servicio también puede estar inactivo. En mi opinión, esto es similar a no tener pruebas para las consultas y confiar en las pruebas de integración / sistema para encontrar los problemas. Dicho esto, si los datos de la API rara vez cambian y la API en sí está casi siempre activa, entonces esta podría ser una opción viable. La mayoría de las API no se ajustan a esta descripción.

Eventualmente, todo se reduce a cuán importantes y complejas son estas consultas: si hay más de un puñado y algunas de ellas son lo suficientemente complejas como para que sienta la necesidad de probarlas, invertiría el esfuerzo de configurar una instancia privada para la prueba . Se pagará solo como otras pruebas unitarias.

Michal Tenenberg
fuente
Entonces, básicamente, ¿está diciendo que las pruebas unitarias (# 1) y las pruebas de integración (# 2) son dañinas? Si bien el # 3 puede parecer el mejor entre ellos, también podría ser el más caro. Tiene que mantenerse cada vez que cambia la API. Sin el n. ° 2, no se dará cuenta de posibles cambios de errores en la API real hasta que su aplicación esté en producción (demasiado tarde para tomar medidas). Ok, # 1 parece no necesitarse porque no hay líneas de código para probar ... hoy ... Mañana, cómo sabe ...
Laiv
Estoy diciendo que las malas pruebas son dañinas, definitivamente. Las pruebas escamosas desperdician mucho tiempo y esfuerzo, y hacen que las personas pierdan la fe en las pruebas unitarias en su conjunto. Las pruebas que rompen con los cambios de implementación (# 1) o simplemente al azar cuando los cambios de datos (# 2) no son buenas pruebas.
Michal Tenenberg
La prueba de integración no prueba datos. Eso es. No pueden romper las pruebas, solo validan la integración. La prueba no es cuestión de fe, es cuestión de tener buenos hábitos que agreguen valor a la aplicación
Laiv