Un test unitario è considerato fragile se fallisce quando la logica aziendale cambia?

27

Vedi il codice qui sotto; verifica se una persona con genere femminile è eleggibile per l'offerta 1:

[Fact]
public void ReturnsFalseWhenGivenAPersonWithAGenderOfFemale()
{
    var personId = Guid.NewGuid();
    var gender = "F";
    var person = new Person(personId, gender);

    var id = Guid.NewGuid();
    var offer1 = new Offer1(id,"Offer1");
    Assert.False(offer1.IsEligible(person));
}

Questo test di unità ha esito positivo. Tuttavia, fallirà se "Offer1" verrà offerto alle donne in futuro.

È accettabile dire che se la logica aziendale che circonda l'offerta 1 cambia, allora il test dell'unità deve cambiare. Si noti che in alcuni casi (per alcune offerte) la logica aziendale viene modificata nel database in questo modo:

update Offers set Gender='M' where offer=1;

e in alcuni casi nel modello di dominio come questo:

if (Gender=Gender.Male)
{
  //do something
}

Si noti inoltre che in alcuni casi la logica del dominio dietro offre modifiche periodiche e in alcuni casi no.

    
posta w0051977 24.12.2018 - 13:02
fonte

2 risposte

77

Questo non è fragile nel solito senso. Un test unitario è considerato fragile se si rompe a causa di cambiamenti di implementazione che non influenzano il comportamento sotto test. Ma se la stessa logica di business cambia, allora un test di questa logica è supposto da interrompere.

Detto questo, se la logica aziendale cambia davvero spesso, forse non è opportuno codificare le aspettative nei test unitari. Invece è possibile verificare se le configurazioni nel database influenzano le offerte come previsto.

Il nome del test Returns False When Given A Person With A Gender Of Female non descrive una regola aziendale. Una regola aziendale sarebbe qualcosa come Offers Applicable to M should not be applied to persons of gender F .

Quindi potresti scrivere un test che conferma che se un'offerta è definita come applicabile solo alle persone di tipo M, quindi una persona di tipo F non sarà indicata come idonea per questo. Questo test garantirà che la logica funzioni anche se cambia la configurazione delle offerte specifiche.

    
risposta data 24.12.2018 - 13:28
fonte
14

Quando la proprietà è definita nel database di produzione (o un clone per il test), questo non è un test di unità . Un test unitario controlla un'unità di lavoro e non richiede un particolare stato esterno per funzionare. Ciò presuppone che Offer1 sia definita nel database come un'offerta di soli uomini. Questo è lo stato esterno. Quindi questo è più di un test di integrazione , in particolare un sistema o accettazione . Nota che i test di accettazione spesso non sono script (non vengono eseguiti in un framework di test ma eseguiti manualmente da esseri umani).

Quando la proprietà viene definita nel modello di dominio con un'istruzione if , lo stesso test è un test unitario. E potrebbe essere fragile Ma il vero problema è che il codice è fragile. Come regola generale, il codice sarà più resiliente se il comportamento aziendale è configurabile anziché codificato. Perché una distribuzione rapida per risolvere un piccolo errore di codifica dovrebbe essere rara. Ma un requisito aziendale che cambia senza preavviso è solo un martedì (qualcosa che succede settimanalmente).

È possibile che si stia utilizzando un framework di test unitario per eseguire il test. Ma i framework per le unit test non sono limitati ai test unitari in esecuzione. Possono anche eseguire test di integrazione.

Se stavi scrivendo un test unitario, creerai sia person che offer1 da zero senza fare affidamento sullo stato del database. Qualcosa come

[Fact]
public void ReturnsFalseWhenGivenAPersonWithAGenderOfFemale()
{
    var personId = Guid.NewGuid();
    var gender = "F";
    var person = new Person(personId, gender);

    var id = Guid.NewGuid();
    var offer1 = new Offer1(id, "ReturnsFalseWhenGivenAPersonWithAGenderOfFemale");
    offer1.markLimitedToGender("M");

    Assert.False(offer1.IsEligible(person));
}

Si noti che questo non cambia in base alla logica aziendale. Non sta asserendo che offer1 rifiuta le femmine. Sta facendo offer1 del tipo di offerta che respinge le donne.

È possibile creare e configurare il database come parte del test. In C #, usando NUnit, o in JUnit di Java, devi impostare il database in un metodo Setup . Presumibilmente la tua struttura di test ha una nozione simile. In tale metodo, è possibile inserire record nel database con SQL.

Se è difficile per te scrivere codice che sostituisce un database di test per il database di produzione, sembra una debolezza di test nella tua applicazione. Per il test, sarebbe meglio usare qualcosa come l'iniezione di dipendenza che consente la sostituzione. Quindi è possibile scrivere test che sono indipendenti dalle attuali regole aziendali.

Un vantaggio collaterale di questo è che è spesso più semplice per il proprietario dell'azienda (non necessariamente il proprietario dell'azienda, più come la persona responsabile di questo prodotto nella gerarchia aziendale) per configurare direttamente le regole aziendali. Perché se si dispone di questo tipo di framework tecnico, è facile consentire al proprietario dell'azienda di utilizzare un'interfaccia utente (UI) per configurare l'offerta. Il proprietario dell'attività commerciale selezionerebbe la limitazione nell'interfaccia utente e emetterebbe la chiamata markLimitedToGender("M") . Quindi, quando l'offerta viene mantenuta nel database, la memorizzerebbe. Ma non avresti bisogno di archiviare l'offerta per usarla. Quindi i tuoi test potrebbero creare e configurare un'offerta che non esiste nel database.

Nel tuo sistema come descritto, il proprietario dell'azienda dovrebbe inserire una richiesta al gruppo tecnico, che emetterebbe l'SQL appropriato e aggiornerà i test. Oppure il gruppo tecnico deve modificare il codice e i test (o testare il codice). Sembra un approccio piuttosto pesante. Puoi farlo. Ma il tuo software (non solo i tuoi test) sarebbe meno fragile se non dovessi farlo.

TL; DR : puoi scrivere test come questo, ma potresti stare meglio scrivendo il tuo software in modo da non doverlo fare.

    
risposta data 24.12.2018 - 18:00
fonte

Leggi altre domande sui tag