Verranno testati i messaggi in uscita dall'oggetto in prova?

3

Stavo guardando una registrazione di una conferenza di Sandi Metz sui test. Una delle cose con cui ho avuto a che fare è stata che ha detto di non testare gli output dell'oggetto sottoposto a test (il suo esempio erano i messaggi di query poiché utilizza rails .) Qui è un sommario che riassume ciò che stava dicendo e qui è il discorso completo .

Diciamo che ho qualche oggetto A che voglio testare e A è sul lato client della mia applicazione web. Ci vuole un po 'di API e voglio assicurarmi che stia richiedendo dati dalla parte destra dell'API (ad esempio un PATCH a /some/url con un po' di body di payload.)

Mi sembra parte del contratto dell'oggetto? Sto testando il mio codice nel modo corretto? Sto interpretando male il punto che Sandi stava cercando di trasmettere? Mi sto davvero concentrando su non per la scrittura di test fragili, ma testiamo ancora ciò che è necessario testare.

    
posta Adam Thompson 29.08.2018 - 02:42
fonte

4 risposte

2

Penso che tu stia interpretando male il discorso.

What to test?

  • Test incoming query messages by making assertions about what they send back
  • Test incoming command messages by making assertions about direct public side effects

Quindi verifichi cosa sia l''uscita' dell'oggetto. Quello che non testate è come raggiunge quell'output, anche se usa "Messaggi di output" su altri oggetti.

Quindi nel tuo esempio, no non ti importa di quale API il tuo cliente parla e come. Tutto quello che ti interessa è che quando chiami il cliente, ti dà il risultato giusto.

    
risposta data 29.08.2018 - 12:27
fonte
2

Dovremmo sforzarci di testare le funzionalità, non i dettagli di implementazione . Molto semplicemente, le caratteristiche sono richieste dal cliente / proprietario del prodotto. I dettagli di implementazione sono le scelte fatte dagli sviluppatori di cui il proprietario / proprietario del prodotto non è a conoscenza o di cui non si cura.

Per semplificare lo scenario, considera di testare se il messaggio di errore restituito da A è il messaggio corretto.

Di solito, non dovresti testarlo. Il messaggio di errore specifico è un dettaglio di implementazione. Che sia "Error 001 occurred!" o "Cannot find user in database!" o "Kan de gebruiker niet vinden!" (traduzione olandese) è irrilevante. Quello che cerchiamo di testare è il suo comportamento . Pertanto, possiamo testare se viene generata un'eccezione e if che l'eccezione generata era del tipo corretto, ma non dovremmo testare il messaggio dell'eccezione.

C'è un'eccezione a questo:
Quando l'analisi funzionale (non solo quella tecnica) definisce esplicitamente il messaggio di errore. Ad esempio, considera che stiamo costruendo un'API per un cliente che prevede di ricevere un'eccezione con il messaggio "USER_NOT_FOUND" quando viene richiesto un utente sconosciuto.
In questo caso, il messaggio di errore non è più un dettaglio di implementazione, è una funzionalità reale dell'applicazione. Pertanto, dobbiamo testarlo.

Applicando lo stesso principio al tuo esempio:

Let's say I have some object A that I want to test and A is on the client-side of my web application. It takes to some API and I want to make sure it is requesting data from the right portion of the API (e.g. a PATCH to /some/url with some body payload.)

Puoi sempre testare se A invia una richiesta web. Ma l'URL specifico che usa non dovrebbe sempre essere testato.

Se l'API e l'applicazione client sono considerate una soluzione / progetto commerciale, la loro comunicazione (ad esempio nomi URL specifici) è un dettaglio dell'implementazione e non dovrebbe essere testato.

Se l'API esiste già e non puoi cambiarla, utilizzarla correttamente fa parte dei requisiti dell'applicazione client e, pertanto, può essere testata in modo significativo.

Ciò si riflette anche nella sintesi che hai collegato:

What NOT to test?

  • Messages that are sent from within the object itself (e.g. private methods).
  • Outgoing query messages (as they have no public side effects)
  • Outgoing command messages (use mocks and set expectations on behaviour to ensure rest of your code pass without error)
  • Incoming messages that have no dependants (just remove those tests)

Note: there is no point in testing outgoing messages because they should be tested as incoming messages on another object

    
risposta data 29.08.2018 - 10:23
fonte
1

I really am focusing on not writing brittle tests but that still test what need to be tested.

OK, se questo è il tuo obiettivo (ed è buono ...)

Una delle cose che rende i test fragili è che il test diventa accoppiato ai dettagli di implementazione. Le classi sono come un modulo, in quella parte della motivazione per la creazione di una nuova classe è che abbiamo preso una decisione su come la soluzione dovrebbe essere implementata, e vogliamo limitare la quantità di codice che conosce la decisione che abbiamo preso. Vedi sui criteri per essere usato in sistemi di decomposizione in moduli (Parnas, 1982).

In particolare, l'accoppiamento del test a ciò che un comando dovrebbe fare è, da questa prospettiva, rischioso. Cerca invece la query che puoi invocare per confermare che il comando abbia eseguito la cosa prevista.

Ora, hai assolutamente ragione che da qualche parte c'è un po 'di codice che, dati gli input x, y, z, dovrebbe produrre una particolare richiesta http. E vorrete scrivere un test per quel codice (facile - è una domanda). Ma scrivere un test per confermare che A chiama questa funzione? Yikes.

Un discorso che può essere d'aiuto per il tuo esempio specifico è Confini di Gary Bernhardt. Parte del punto è mantenere il confine sottile; se il codice non sta facendo nulla di sorprendente, allora è facile scriverlo in un modo che è troppo semplice per nascondere un errore. Quando abbiamo bisogno di scrivere test di complicati codici che parlano al confine, possiamo facilmente sostituire un confine reale con i duplicati di test (si pensi a porte e adattatori).

Esistono, naturalmente, alcune strategie per testare le interazioni attraverso un limite del processo. Test del contratto, utilizzando strumenti come Patto , è una possibilità. La mia esperienza è stata che queste strategie sono più costose e quindi si desidera limitarle all'estremità sottile della piramide di test.

Nota: la patch HTTP non è sicura , che è un altro modo per dire che è un " comando". Quindi, nella griglia di Sandi, rientra nel attendi di inviare bucket, con il grandi avvertimenti lettera sulle implicazioni della deriva API.

I "comandi" HTTP sono un po 'confusi, perché restituiscono messaggi e Sandi dice che i comandi non restituiscono nulla? E questo è vero, in un ambiente in cui lo schema CQS ha un senso e hai garanzie di consegna dei messaggi forti. Ma la rete non è affidabile , e hai bisogno di una sorta di riconoscimento per sapere che il messaggio di comando è passato.

Quindi potresti finire con due diversi tipi di test: uno in cui il test double per il client http è un simulato , e tu "prevedi" la richiesta HTTP corretta da inviare, e poi un altro tipo in cui il test double del client http è uno "stub" che restituisce alcune risposte fisse al soggetto del test.

Entrambi questi tipi di test dipendono dal fatto che i duplicati del test rappresentano fedelmente il contratto API tra il client e il server, quindi dovrete stare attenti, in particolare, essere disposti a scartare i test e iniziare sopra se qualcuno introduce una modifica all'indietro incompatibile con quella API.

    
risposta data 29.08.2018 - 07:10
fonte
0

Per prima cosa, assicurati che tu e Sandi abbiate le stesse priorità. Al di fuori del mondo accademico e della ricerca, il software eng non è una scienza, dal momento che è fatto per volere di uomini d'affari e gli affari non sono una scienza. Dichiarando limiti severi alla sua strategia di test, Sandi punta alla velocità di esecuzione e alla velocità del refactoring deduplicando il suo codice di test. Tu, d'altra parte, potresti scrivere software incorporato per un pacemaker: in tal caso, sarai meno preoccupato della duplicazione della copertura piuttosto che non abbastanza.

In secondo luogo, questa limitazione dei test che propone probabilmente funziona alla grande insieme ad altre pratiche che non menziona, come forse l'inversione di dipendenza, o quella su cui lei tocchi, come i buoni test contrattuali separati dai test unitari. Di per sé, i tuoi istinti sono corretti; no, non è valido dire che hai testato un oggetto su un oggetto senza verificare le modifiche dello stato che ha apportato ai collaboratori. Penso che stia solo sostenendo un certo modo di controllarlo, non che tu debba fallire!

    
risposta data 29.08.2018 - 03:28
fonte