Come testare una funzione il cui unico scopo è interrogare un'API esterna, ma l'API utilizza una sintassi di query complessa?


16

L'unica vera logica è nella sintassi della query per l'API esterna. Non voglio testare se interroga l'API, voglio testare che lo interroga in modo tale da restituire i dati corretti. Ad esempio, alcuni pseudo-codice:

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 esempio più concreto con un'API inventata:

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 query è in una sintassi personalizzata per l'API ed è complessa e ci sono diversi modi per ottenere risultati uguali o simili. Lo scopo della funzione non è quello di ottenere i dati identificati da, idma di trovare un sottoinsieme di altri dati basati su una relazione fuzzy con i dati identificati idche soddisfano anche alcuni altri requisiti. Gli altri requisiti sono sempre gli stessi, idma possono cambiare nel tempo man mano che il sistema viene modificato. Ad esempio, se l'API di esempio ha aggiunto il supporto per le informazioni sulla gravità, potremmo voler modificare la query per utilizzare anche la gravità per perfezionare i risultati. O forse ci viene in mente un modo più efficiente per controllare l'intervallo di temperatura, ma non cambia i risultati.

Quello che voglio testare è che per un dato input idviene restituito il set corretto di dati. Voglio provare questo in modo che se qualcuno incasina la query in modo tale che non restituisca più i dati corretti in base a idciò fallirà, ma voglio anche che le persone siano in grado di modificare la query per perfezionarla senza dover modificare il test.

Opzioni che ho considerato:

  1. Potrei stub l'api, ma sarebbe troppo semplice (controlla che idsia presente nella query e quindi restituisca un set di dati previsto se lo è o un set imprevisto in caso contrario), troppo fragile (controlla che la stringa della query sia esattamente ciò che è nella funzione) o troppo complesso (verificare che la query utilizzata sia sintatticamente corretta e risulti nella restituzione dei dati corretti).

  2. Potrei inviare la query all'api reale, ma i risultati previsti potrebbero cambiare nel tempo man mano che i dati nel sistema esterno cambiano, al di fuori del controllo del sistema di test.

  3. Potrei guardare alla configurazione di un'installazione di prova dell'api reale al fine di controllare i dati che ha, ma è un grande sforzo.

Mi sto orientando verso il n. 2 e sto rendendo questo più un test di integrazione che non viene eseguito spesso e vedo con che frequenza i cambiamenti nei dati del sistema esterno causano l'interruzione del test. Penso che sarebbe più semplice per ora, ma mi chiedo se ci sono alternative a cui non sto pensando o modi migliori per affrontare questo problema. Tutto il consiglio sarebbe apprezzato.


Stavo pensando a questo come un test unitario, ma forse è davvero un test di integrazione o un test di accettazione di basso livello?
Joshua Coady,

2
È un'API di sola lettura? Oppure, sei in grado di scrivere dati su cui puoi verificare in modo affidabile le tue letture ?
svidgen,

Questa domanda è diversa da "come verificare che il mio sql (= sintassi complessa) restituisca i dati corretti"? Con i database di solito hai alcuni test di integrazione che testano la sintassi crud-sql e un fasade repository beffardo per verificare businesslogic
k3b

Risposte:


7

Può sembrare che la convalida della risposta API esterna starebbe testando la nostra funzione, ma non sarebbe del tutto vero. In qualche modo, verificheremo l'API esterna e l'ambiente in cui è in esecuzione l'API.

I nostri test devono essere indirizzati per garantire il comportamento previsto del codice che abbiamo scritto, non quello scritto da terze parti.

In una certa misura, dobbiamo fidarci della corretta funzione delle API e delle librerie su cui facciamo affidamento. Ad esempio, di solito non testiamo i componenti del framework che implementiamo.

Perché lo dico io?

Quello che voglio testare è che per un dato input input viene restituito il set corretto di dati

Cosa verrebbe testato qui? Come hai detto, i dati e la loro correttezza non sono sotto il nostro controllo, quindi limiteremmo il successo della fase di test a un agente esterno che non abbiamo alcun controllo. Questi test sono candidati per diventare non deterministici e definitivamente, non vogliamo questo tipo di test nella nostra pipeline di edifici .

Una preoccupazione diversa è quella di convalidare il contratto. Troverei molto utile un contratto di prova 1 per garantire che l'integrazione funzioni ancora come previsto, prima di qualsiasi rilascio o distribuzione.

Voglio provare questo in modo che se qualcuno incasina la query in modo tale che non stia più restituendo i dati corretti in base all'ID che fallirà

Cosa succede se la query è corretta, ma i dati sono errati a causa di bug nell'API? Non solo i dati sono fuori dal nostro controllo. Anche la logica.

L'implementazione di test funzionali o test end-to-end può essere d'aiuto in questo caso. È possibile affrontare questi test per convalidare determinati percorsi di esecuzione in modo che se le API restituiscono dati errati, ciò probabilmente causerà comportamenti e output imprevisti. D'altro canto, mi aspetterei che l'API generasse errori se le mie query non fossero formattate correttamente.

Ma voglio anche che le persone siano in grado di modificare la query per perfezionarla senza dover modificare anche il test.

Suggerisco di implementare uno strumento a tale scopo. Potrebbe essere semplice come:

  • Una classe che viene eseguita come test ma non appartiene al piano di test
  • Uno script di shell + ricciolo

O qualcosa di più sofisticato. Ad esempio, un client autonomo.

In ogni caso, la funzione sotto la domanda merita due tipi di test:

  • Test unitario. Come hai detto, devi eliminare l'API esterna, ma questo è l'intero scopo dei test unitari. Testare il nostro codice isolando le dipendenze.

  • Test di integrazione. Verificare che il codice non solo invii la richiesta corretta ma che gestisca correttamente il contenuto della risposta, errori, reindirizzamenti, ecc. Effettuare test per tutti questi casi, ma non testare i dati .

Nota a margine: la tua domanda è simile a -come testate le istruzioni SQL dell'app-?

Domande correlate :


1: Potresti essere interessato alla risposta di @ DocBrown su questo argomento


"Il problema (IMO) è che sei troppo concentrato sul test dell'API esterna." - Non vedo nulla che indichi che l'interlocutore è interessato a testare l'API esterna. Inoltre, dici "stub l'API esterna", ma hai qualche suggerimento sul fatto che il richiedente debba usare l'opzione "troppo semplice", l'opzione "troppo fragile", l'opzione "troppo complessa" o una quarta opzione?
Tanner Swett,

La domanda OP sta chiedendo come testare una funzione che chiama un'API esterna. Ma leggendo i suoi dubbi, mi sembra che tenga troppa enfasi sul test della query e dei suoi risultati. Ho formulato 4 suggerimenti: (1) non testare l'API. (2) non utilizzare i test di integrazione come workbench per ottimizzare la query. Crea invece uno strumento. (3) tornando alla domanda principale, esegui il test unitario e di integrazione. Ma non convalidare il contenuto della risposta API. (4) Chiedi al project manager se devono / possono creare una suite di test dell'API esterna come parte del piano di test del progetto.
Laiv,

1
Considero la query stessa come "codice scritto da noi". L'obiettivo finale è il test automatico per avvisarci se abbiamo introdotto un bug nel nostro codice. Portandolo a quello che hai detto sulle dichiarazioni SQL, immagino che sia simile a questo - suppongo che la mia domanda sia simile a come testare il codice che sta eseguendo una query su un'API esterna in un modo in cui l'API risponderà come previsto (supponendo un risposta nominale). Penso che quello che stai dicendo sia di lasciarlo fuori dall'unità e dei test di integrazione, ma se le domande sono di importanza critica, potremmo impostare alcuni altri test automatizzati separatamente per testare l'API esterna dal vivo.
Joshua Coady,

1
IMO, il modo migliore è fare test funzionali, il cambiamento nella clausola where che non sarà mai vera, causerà un comportamento diverso in uno o più dei miei test funzionali. UT sono solo un piccolo pezzo nel piano di test.
Laiv

2
Grazie per essere una cassa di risonanza. Credo che alla fine, anche se la query ha una logica personalizzata, è al di fuori del dominio del test unitario perché la query è un codice che viene "eseguito" al di fuori del sistema in fase di test. Avevo solo bisogno di qualcuno che me lo dicesse più volte in diversi modi prima di vederlo;)
Joshua Coady,

2

Ho visto i controlli di unità che controllano che la stringa di query generata corrisponda a un valore previsto.

Tuttavia. Questo a mio avviso era un uso limitato. La sintassi della query era complicata, probabilmente errata, quindi A c'erano infinite possibilità di controllo e B anche se la stringa fosse stata "correttamente" generata, i risultati imprevisti potevano essere restituiti nell'ambiente live.

Penso che tu abbia ragione per scegliere la tua opzione 2. eseguire test di integrazione contro l'istanza live.

Fintanto che non sono distruttivi, questi sono i primi test che dovresti scrivere, in quanto rileveranno, anche se non identificheranno la causa, alcun errore.

Scegliere l'opzione 3 "distribuire un'istanza di prova con dati fittizi" è superiore. Ma ciò non influisce sulla scrittura del test, poiché è possibile puntare gli stessi test sul server di test se e quando diventa un buon uso del tempo per distribuirne uno.


0

Dipende dall'API, ma se possibile, scegli l'opzione 3 (istanza di test privata).

Stubbing l'API (opzione n. 1) è l'opzione peggiore, a causa dei motivi che hai citato, e percorrere questa strada probabilmente farà più male che bene (molto tempo sprecato).

Correre contro la vera API (opzione n. 2) rende i test traballanti e inaffidabili, e dopo alcuni falsi positivi le persone smetteranno di usarli. Non solo i dati possono cambiare, ma anche il servizio potrebbe non essere attivo. A mio avviso, è come non avere test per le query e fare affidamento su test di integrazione / sistema per trovare i problemi. Detto questo, se i dati dell'API cambiano raramente e l'API stessa è quasi sempre attiva, questa potrebbe essere un'opzione praticabile. La maggior parte delle API non si adatta a questa descrizione.

Alla fine si riduce a quanto siano importanti e complesse queste query: se ce ne sono più di una manciata, e alcune di esse sono abbastanza complesse da farti sentire la necessità di testarle, investirei lo sforzo di creare un'istanza privata per i test . Pagherà per se stesso proprio come altri test unitari.


Quindi, in sostanza, stai dicendo che i test unitari (n. 1) e i test di integrazione (n. 2) sono dannosi? Mentre il n. 3 può sembrare il migliore, potrebbe anche essere il più costoso. Deve essere mantenuto ogni volta che l'API cambia. Senza # 2 non sarai a conoscenza di possibili modifiche ai bug nell'API reale fino a quando l'app non sarà in produzione (troppo tardi per prendere le misure). Ok, il n. 1 sembra non essere seguito perché non ci sono righe di codice da testare ... oggi ... Domani, come lo sa ...
Laiv

Sto dicendo che i test negativi sono dannosi, sicuramente. I test traballanti sprecano molto tempo e fatica e fanno perdere la fiducia ai test unitari nel loro insieme. I test che si interrompono con le modifiche all'implementazione (n. 1) o semplicemente in modo casuale quando le modifiche ai dati (n. 2) non sono buoni test.
Michal Tenenberg,

Il test di integrazione non verifica i dati. Questo è tutto. Non possono interrompere il test, solo convalidare l'integrazione. Il test non è una questione di fede è una questione di buone abitudini che aggiungono valore all'applicazione
Laiv
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.