Domanda

Usando C#, ho bisogno di una classe chiamata User che ha un nome utente, una password, un flag attivo, un nome, un cognome, un nome completo, ecc.

Dovrebbero esserci dei metodi per farlo autenticare E salva un utente.Scrivo semplicemente un test per i metodi?E devo anche preoccuparmi di testare le proprietà poiché sono getter e setter di .Net?

È stato utile?

Soluzione

Molte ottime risposte a questo sono anche sulla mia domanda:"Inizio TDD - Sfide?Soluzioni?Consigli?"

Posso anche consigliarti di dare un'occhiata al mio post sul blog (che è stato in parte ispirato dalla mia domanda), ho ricevuto dei buoni feedback a riguardo.Vale a dire:

Non so da dove iniziare?

  • Ricominciare da capo.Pensa solo a scrivere test quando scrivi un nuovo codice.Questo può essere la ricostruzione del vecchio codice o una funzionalità completamente nuova.
  • Inizia in modo semplice.Non andare a correre e cercare di mettere la testa attorno a un framework di test, oltre ad essere TDD-esque.Debug.Assert funziona correttamente.Usalo come punto di partenza.Non scherza con il tuo progetto o crea dipendenze.
  • Inizia in modo positivo.Stai cercando di migliorare il tuo mestiere, sentiti bene.Ho visto molti sviluppatori là fuori che sono felici di ristagnare e non provare cose nuove per migliorare se stessi.Stai facendo la cosa giusta, ricorda questo e ti aiuterà a arrenderti.
  • Inizia pronto per una sfida.È abbastanza difficile iniziare a partecipare ai test.Aspettatevi una sfida, ma ricorda: le sfide possono essere superate.

Prova solo per quello che ti aspetti

Ho avuto problemi reali quando ho iniziato perché ero costantemente seduto lì cercando di capire ogni possibile problema che poteva verificarsi e quindi cercare di testarlo e correggere.Questo è un modo rapido per il mal di testa.I test dovrebbero essere un vero processo di Yagni.Se sai che c'è un problema, scrivi un test per questo.Altrimenti, non preoccuparti.

Prova solo una cosa

Ogni caso di test dovrebbe testare sempre una cosa.Se ti ritrovi a mettere "e" nel nome del caso, stai facendo qualcosa di sbagliato.

Spero che questo significhi che possiamo passare da "getter e setter" :)

Altri suggerimenti

Metti alla prova il tuo codice, non la lingua.

Un test unitario come:

Integer i = new Integer(7);
assert (i.instanceOf(integer));

è utile solo se stai scrivendo un compilatore e c'è una possibilità diversa da zero che tuo instanceof il metodo non funziona.

Non testare cose che puoi fare affidamento sulla lingua per far rispettare.Nel tuo caso, mi concentrerei sui metodi di autenticazione e salvataggio e scriverei test che assicurassero che potessero gestire con garbo valori null in uno o tutti questi campi.

Questo mi ha portato a testare le unità e mi ha reso molto felice

Abbiamo appena iniziato a fare test unitari.Per molto tempo sapevo che sarebbe stato bello iniziare a farlo ma non avevo idea di come iniziare e, soprattutto, cosa testare.

Poi abbiamo dovuto riscrivere un pezzo importante di codice nel nostro programma di contabilità.Questa parte era molto complessa poiché prevedeva molti scenari diversi.La parte di cui parlo è un metodo per pagare le fatture di vendita e/o di acquisto già inserite nel sistema contabile.

Semplicemente non sapevo come iniziare a codificarlo, poiché c'erano così tante diverse opzioni di pagamento.Una fattura potrebbe essere di $ 100 ma il cliente ha trasferito solo $ 99.Forse hai inviato fatture di vendita a un cliente ma hai anche acquistato da quel cliente.Quindi lo hai venduto per 300 dollari ma hai comprato per 100 dollari.Puoi aspettarti che il tuo cliente ti paghi $ 200 per saldare il saldo.E cosa succederebbe se vendessi per 500$ ma il cliente ti pagasse solo 250$?

Quindi avevo un problema molto complesso da risolvere con molte possibilità che uno scenario avrebbe funzionato perfettamente ma sarebbe stato sbagliato su un altro tipo di combinazione fattura/pagamento.

È qui che i test unitari sono venuti in soccorso.

Ho iniziato a scrivere (all'interno del codice di test) un metodo per creare un elenco di fatture, sia di vendita che di acquisto.Poi ho scritto un secondo metodo per creare il pagamento vero e proprio.Normalmente un utente immette tali informazioni tramite un'interfaccia utente.

Poi ho creato il primo TestMethod, testando il pagamento semplicissimo di una singola fattura senza sconti sul pagamento.Tutta l'azione nel sistema avverrebbe quando un pagamento bancario verrebbe salvato nel database.Come puoi vedere, ho creato una fattura, creato un pagamento (una transazione bancaria) e salvato la transazione su disco.Nelle mie affermazioni ho inserito quelli che dovrebbero essere i numeri corretti che finiscono nella transazione bancaria e nella fattura collegata.Controllo il numero di pagamenti, gli importi dei pagamenti, l'importo dello sconto e il saldo della fattura dopo la transazione.

Dopo l'esecuzione del test, andavo al database e ricontrollavo se quello che mi aspettavo fosse presente.

Dopo Ho scritto il test, ho iniziato a codificare il metodo di pagamento (parte della classe BankHeader).Nella codifica mi sono preoccupato solo del codice per far passare il primo test.Non avevo ancora pensato agli altri scenari, più complessi.

Ho eseguito il primo test, corretto un piccolo bug finché il test non è stato superato.

Poi ho iniziato a scrivere il secondo test, questa volta lavorando con uno sconto sul pagamento.Dopo aver scritto il test ho modificato il metodo di pagamento per supportare gli sconti.

Durante il test di correttezza con uno sconto sul pagamento, ho testato anche il pagamento semplice.Entrambi i test dovrebbero ovviamente essere superati.

Poi sono passato agli scenari più complessi.

1) Pensa a un nuovo scenario

2) Scrivi un test per quello scenario

3) Esegui quel singolo test per vedere se passerebbe

4) In caso contrario, eseguirei il debug e modificherei il codice finché non passerebbe.

5) Durante la modifica del codice ho continuato a eseguire tutti i test

È così che sono riuscito a creare il mio metodo di pagamento molto complesso.Senza test unitari non sapevo come iniziare a programmare, il problema sembrava travolgente.Con i test ho potuto iniziare con un metodo semplice ed estenderlo passo dopo passo con la certezza che gli scenari più semplici funzionerebbero comunque.

Sono sicuro che l'utilizzo del test unitario mi ha risparmiato alcuni giorni (o settimane) di codifica e garantisce più o meno la correttezza del mio metodo.

Se in seguito penso a un nuovo scenario, posso semplicemente aggiungerlo ai test per vedere se funziona o meno.In caso contrario, posso modificare il codice ma essere comunque sicuro che gli altri scenari funzionino correttamente.Ciò farà risparmiare giorni e giorni nella fase di manutenzione e correzione dei bug.

Sì, anche il codice testato può ancora contenere bug se un utente fa cose a cui non avevi pensato o che gli hai impedito di fare

Di seguito sono riportati solo alcuni dei test che ho creato per testare il mio metodo di pagamento.

public class TestPayments
{
    InvoiceDiaryHeader invoiceHeader = null;
    InvoiceDiaryDetail invoiceDetail = null;
    BankCashDiaryHeader bankHeader = null;
    BankCashDiaryDetail bankDetail = null;



    public InvoiceDiaryHeader CreateSales(string amountIncVat, bool sales, int invoiceNumber, string date)
    {
        ......
        ......
    }

    public BankCashDiaryHeader CreateMultiplePayments(IList<InvoiceDiaryHeader> invoices, int headerNumber, decimal amount, decimal discount)
    {
       ......
       ......
       ......
    }


    [TestMethod]
    public void TestSingleSalesPaymentNoDiscount()
    {
        IList<InvoiceDiaryHeader> list = new List<InvoiceDiaryHeader>();
        list.Add(CreateSales("119", true, 1, "01-09-2008"));
        bankHeader = CreateMultiplePayments(list, 1, 119.00M, 0);
        bankHeader.Save();

        Assert.AreEqual(1, bankHeader.BankCashDetails.Count);
        Assert.AreEqual(1, bankHeader.BankCashDetails[0].Payments.Count);
        Assert.AreEqual(119M, bankHeader.BankCashDetails[0].Payments[0].PaymentAmount);
        Assert.AreEqual(0M, bankHeader.BankCashDetails[0].Payments[0].PaymentDiscount);
        Assert.AreEqual(0, bankHeader.BankCashDetails[0].Payments[0].InvoiceHeader.Balance);
    }

    [TestMethod]
    public void TestSingleSalesPaymentDiscount()
    {
        IList<InvoiceDiaryHeader> list = new List<InvoiceDiaryHeader>();
        list.Add(CreateSales("119", true, 2, "01-09-2008"));
        bankHeader = CreateMultiplePayments(list, 2, 118.00M, 1M);
        bankHeader.Save();

        Assert.AreEqual(1, bankHeader.BankCashDetails.Count);
        Assert.AreEqual(1, bankHeader.BankCashDetails[0].Payments.Count);
        Assert.AreEqual(118M, bankHeader.BankCashDetails[0].Payments[0].PaymentAmount);
        Assert.AreEqual(1M, bankHeader.BankCashDetails[0].Payments[0].PaymentDiscount);
        Assert.AreEqual(0, bankHeader.BankCashDetails[0].Payments[0].InvoiceHeader.Balance);
    }

    [TestMethod]
    [ExpectedException(typeof(ApplicationException))]
    public void TestDuplicateInvoiceNumber()
    {
        IList<InvoiceDiaryHeader> list = new List<InvoiceDiaryHeader>();
        list.Add(CreateSales("100", true, 2, "01-09-2008"));
        list.Add(CreateSales("200", true, 2, "01-09-2008"));

        bankHeader = CreateMultiplePayments(list, 3, 300, 0);
        bankHeader.Save();
        Assert.Fail("expected an ApplicationException");
    }

    [TestMethod]
    public void TestMultipleSalesPaymentWithPaymentDiscount()
    {
        IList<InvoiceDiaryHeader> list = new List<InvoiceDiaryHeader>();
        list.Add(CreateSales("119", true, 11, "01-09-2008"));
        list.Add(CreateSales("400", true, 12, "02-09-2008"));
        list.Add(CreateSales("600", true, 13, "03-09-2008"));
        list.Add(CreateSales("25,40", true, 14, "04-09-2008"));

        bankHeader = CreateMultiplePayments(list, 5, 1144.00M, 0.40M);
        bankHeader.Save();

        Assert.AreEqual(1, bankHeader.BankCashDetails.Count);
        Assert.AreEqual(4, bankHeader.BankCashDetails[0].Payments.Count);
        Assert.AreEqual(118.60M, bankHeader.BankCashDetails[0].Payments[0].PaymentAmount);
        Assert.AreEqual(400, bankHeader.BankCashDetails[0].Payments[1].PaymentAmount);
        Assert.AreEqual(600, bankHeader.BankCashDetails[0].Payments[2].PaymentAmount);
        Assert.AreEqual(25.40M, bankHeader.BankCashDetails[0].Payments[3].PaymentAmount);

        Assert.AreEqual(0.40M, bankHeader.BankCashDetails[0].Payments[0].PaymentDiscount);
        Assert.AreEqual(0, bankHeader.BankCashDetails[0].Payments[1].PaymentDiscount);
        Assert.AreEqual(0, bankHeader.BankCashDetails[0].Payments[2].PaymentDiscount);
        Assert.AreEqual(0, bankHeader.BankCashDetails[0].Payments[3].PaymentDiscount);

        Assert.AreEqual(0, bankHeader.BankCashDetails[0].Payments[0].InvoiceHeader.Balance);
        Assert.AreEqual(0, bankHeader.BankCashDetails[0].Payments[1].InvoiceHeader.Balance);
        Assert.AreEqual(0, bankHeader.BankCashDetails[0].Payments[2].InvoiceHeader.Balance);
        Assert.AreEqual(0, bankHeader.BankCashDetails[0].Payments[3].InvoiceHeader.Balance);
    }

    [TestMethod]
    public void TestSettlement()
    {
        IList<InvoiceDiaryHeader> list = new List<InvoiceDiaryHeader>();
        list.Add(CreateSales("300", true, 43, "01-09-2008")); //Sales
        list.Add(CreateSales("100", false, 6453, "02-09-2008")); //Purchase

        bankHeader = CreateMultiplePayments(list, 22, 200, 0);
        bankHeader.Save();

        Assert.AreEqual(1, bankHeader.BankCashDetails.Count);
        Assert.AreEqual(2, bankHeader.BankCashDetails[0].Payments.Count);
        Assert.AreEqual(300, bankHeader.BankCashDetails[0].Payments[0].PaymentAmount);
        Assert.AreEqual(-100, bankHeader.BankCashDetails[0].Payments[1].PaymentAmount);
        Assert.AreEqual(0, bankHeader.BankCashDetails[0].Payments[0].InvoiceHeader.Balance);
        Assert.AreEqual(0, bankHeader.BankCashDetails[0].Payments[1].InvoiceHeader.Balance);
    }

Se sono davvero banali, allora non preoccuparti di testarli.Ad esempio, se sono implementati in questo modo;

public class User
{
    public string Username { get; set; }
    public string Password { get; set; }
}

Se, d'altra parte, stai facendo qualcosa di intelligente (come crittografare e decrittografare la password nel getter/setter), fai un test.

La regola è che devi testare ogni pezzo di logica che scrivi.Se hai implementato alcune funzionalità specifiche nei getter e nei setter, penso che valga la pena testarle.Se assegnano valori solo ad alcuni campi privati, non preoccuparti.

Questa domanda sembra essere una questione di dove si traccia il confine su quali metodi vengono testati e quali no.

I setter e getter per l'assegnazione del valore sono stati creati pensando alla coerenza e alla crescita futura e prevedendo che con il passare del tempo il setter/getter potrebbe evolversi in operazioni più complesse.Avrebbe senso mettere in atto test unitari di tali metodi, anche per motivi di coerenza e crescita futura.

L'affidabilità del codice, soprattutto durante le modifiche per aggiungere funzionalità aggiuntive, è l'obiettivo principale.Non sono a conoscenza di nessuno che sia mai stato licenziato per aver incluso setter/getter nella metodologia di test, ma sono certo che esistano persone che avrebbero voluto testare metodi che l'ultima volta di cui erano a conoscenza o che possono ricordare erano semplici wrapper set/get, ma non era così più a lungo il caso.

Forse un altro membro del team ha ampliato i metodi set/get per includere la logica che ora deve essere testata ma non ha poi creato i test.Ma ora il tuo codice chiama questi metodi e non sei consapevole che sono cambiati e necessitano di test approfonditi, e i test che fai in fase di sviluppo e QA non attivano il difetto, ma i dati aziendali reali il primo giorno di rilascio lo fanno attivarlo.

I due compagni di squadra ora discuteranno su chi ha lasciato cadere la palla e non è riuscito a eseguire i test unitari quando il set/viene trasformato per includere una logica che può fallire ma non è coperta da un test unitario.Il compagno di squadra che originariamente ha scritto il set/gets avrà più facilità a uscire da questa fase di pulizia se i test sono stati implementati fin dal primo giorno sul semplice set/gets.

La mia opinione è che pochi minuti di tempo "sprecato" coprendo TUTTI i metodi con test unitari, anche quelli banali, potrebbero risparmiare giorni di mal di testa lungo la strada e perdita di denaro/reputazione dell'azienda e perdita del lavoro di qualcuno.

E il fatto che tu abbia racchiuso metodi banali con test unitari potrebbe essere visto da quel compagno di squadra junior quando cambia i metodi banali in metodi non banali e li spinge ad aggiornare il test, e ora nessuno è nei guai perché il difetto è stato contenuto dal raggiungere la produzione.

Il modo in cui codifichiamo e la disciplina che può essere vista dal nostro codice possono aiutare gli altri.

Un'altra risposta canonica.Questo, credo, da Ron Jeffries:

Testa solo il codice su cui vuoi che funzioni.

Testare il codice boilerplate è una perdita di tempo, ma come dice Slavo, se aggiungi un effetto collaterale ai tuoi getter/setter, dovresti scrivere un test per accompagnare quella funzionalità.

Se stai eseguendo uno sviluppo basato sui test, dovresti prima scrivere il contratto (ad esempio l'interfaccia), quindi scrivere i test per esercitare quell'interfaccia che documenta i risultati/comportamenti attesi. Poi scrivi i tuoi metodi da soli, senza toccare il codice nei test unitari.Infine, prendi uno strumento di copertura del codice e assicurati che i tuoi test esercitino tutti i percorsi logici nel tuo codice.

Codice davvero banale come getter e setter che non hanno comportamenti aggiuntivi rispetto all'impostazione di un campo privato sono eccessivi da testare.Nella versione 3.0 C# ha anche dello zucchero sintattico in cui il compilatore si occupa del campo privato, quindi non è necessario programmarlo.

Di solito scrivo molti test molto semplici per verificare il comportamento che mi aspetto dalle mie lezioni.Anche se si tratta di cose semplici come sommare due numeri.Passo spesso dallo scrivere un semplice test allo scrivere alcune righe di codice.La ragione di ciò è che posso modificare il codice senza aver paura di rompere cose a cui non avevo pensato.

Dovresti testare tutto.In questo momento hai getter e setter, ma un giorno potresti cambiarli in qualche modo, magari per fare validazione o qualcos'altro.I test che scrivi oggi verranno utilizzati domani per assicurarti che tutto continui a funzionare come al solito.Quando scrivi il test, dovresti dimenticare considerazioni come "in questo momento è banale".In un contesto agile o basato sui test dovresti testare assumendo il refactoring futuro.Inoltre, hai provato a inserire valori davvero strani come stringhe estremamente lunghe o altri contenuti "cattivi"?Beh, dovresti...non dare mai per scontato quanto gravemente il tuo codice possa essere abusato in futuro.

In generale trovo che scrivere test utente approfonditi sia da un lato estenuante.D'altro canto, però, ti fornisce sempre informazioni preziose su come dovrebbe funzionare la tua applicazione e ti aiuta a scartare presupposti facili (e falsi) (come:il nome utente avrà sempre una lunghezza inferiore a 1000 caratteri).

Per moduli semplici che potrebbero finire in un toolkit o in un tipo di progetto open source, dovresti testare il più possibile includendo i banali getter e setter.La cosa che vuoi tenere a mente è che generare uno unit test mentre scrivi un particolare modulo è abbastanza semplice e diretto.L'aggiunta di getter e setter è un codice minimo e può essere gestita senza pensarci troppo.Tuttavia, una volta inserito il codice in un sistema più grande, questo sforzo aggiuntivo può proteggerti dalle modifiche nel sistema sottostante, come le modifiche al tipo in una classe base.Testare tutto è il modo migliore per avere una regressione completa.

Non fa male scrivere test unitari per i tuoi getter e setter.In questo momento, potrebbero semplicemente eseguire operazioni di get/set di campi dietro le quinte, ma in futuro potresti avere una logica di convalida o dipendenze tra proprietà che devono essere testate.È più facile scriverlo ora mentre ci pensi e poi ricordarti di aggiornarlo se mai arriverà quel momento.

in generale, quando un metodo è definito solo per determinati valori, testare i valori su e oltre il confine di ciò che è accettabile.In altre parole, assicurati che il tuo metodo faccia quello che dovrebbe fare, ma niente di più.Questo è importante, perché quando stai per fallire, vuoi fallire presto.

Nelle gerarchie di ereditarietà, assicurati di testare LSP conformità.

Testare getter e setter predefiniti non mi sembra molto utile, a meno che tu non abbia intenzione di fare qualche validazione in seguito.

Per quanto ho capito, i test unitari nel contesto dello sviluppo agile, Mike, sì, devi testare getter e setter (supponendo che siano visibili pubblicamente).L'intero concetto di unit test è testare l'unità software, che in questo caso è una classe, come a scatola nera.Poiché getter e setter sono visibili esternamente, è necessario testarli insieme a Authenticate e Save.

Se i metodi Authenticate e Save utilizzano le proprietà, i test toccheranno indirettamente le proprietà.Finché le proprietà forniscono solo accesso ai dati, non dovrebbero essere necessari test espliciti (a meno che non si opti per una copertura del 100%).

Vorrei mettere alla prova i tuoi getter e setter.A seconda di chi scrive il codice, alcune persone cambiano il significato dei metodi getter/setter.Ho visto l'inizializzazione delle variabili e altre convalide come parte dei metodi getter.Per testare questo genere di cose, vorresti che i test unitari coprissero esplicitamente quel codice.

Personalmente "testerei tutto ciò che può rompersi" e il semplice getter (o anche le migliori proprietà automatiche) non si romperà.Non ho mai avuto un errore in una semplice istruzione di reso e quindi non ho mai eseguito test per loro.Se i getter avessero dei calcoli al loro interno o qualche altra forma di istruzioni, aggiungerei sicuramente dei test.

Personalmente utilizzo Moq come framework di oggetti finti e quindi verificare che il mio oggetto chiami gli oggetti circostanti come dovrebbe.

Devi coprire l'esecuzione di ogni metodo della classe con UT e controllare il valore restituito dal metodo.Ciò include getter e setter, soprattutto nel caso in cui i membri (proprietà) siano classi complesse, che richiedono un'ampia allocazione di memoria durante la loro inizializzazione.Chiama il setter con una stringa molto grande, ad esempio (o qualcosa con simboli greci) e controlla che il risultato sia corretto (non troncato, la codifica è buona ecc.)

Ciò vale anche per gli interi semplici: cosa succede se passi long anziché intero?Questo è il motivo per cui scrivi UT :)

Non testerei l'impostazione effettiva delle proprietà.Sarei più preoccupato di come queste proprietà vengono popolate dal consumatore e con cosa le popolano.Con qualsiasi test, è necessario valutare i rischi con il tempo/costo del test.

Dovresti testare "ogni blocco di codice non banale" utilizzando test unitari il più lontano possibile.

Se le tue proprietà sono banali ed è improbabile che qualcuno vi introduca un bug, allora dovrebbe essere sicuro non sottoporle a test unitari.

I tuoi metodi Authenticate() e Save() sembrano buoni candidati per i test.

Idealmente, avresti eseguito i test unitari mentre scrivevi la lezione.Questo è il modo in cui dovresti farlo quando usi lo sviluppo basato sui test.Aggiungi i test man mano che implementi ciascun punto funzione, assicurandoti di coprire anche i casi limite con il test.

Scrivere i test in seguito è molto più doloroso, ma fattibile.

Ecco cosa farei nella tua posizione:

  1. Scrivi una serie di test di base che mettono alla prova la funzione principale.
  2. Ottieni NCover ed eseguilo sui tuoi test.La copertura del tuo test sarà probabilmente intorno al 50% a questo punto.
  3. Continua ad aggiungere test che coprano i tuoi casi limite finché non ottieni una copertura di circa l'80%-90%

Questo dovrebbe darti un bel set funzionante di test unitari che fungerà da buon buffer contro le regressioni.

L'unico problema con questo approccio è che il codice deve esserlo progettato essere testabile in questo modo.Se hai commesso degli errori di accoppiamento nella fase iniziale, non sarai in grado di ottenere una copertura elevata molto facilmente.

Questo è il motivo per cui è davvero importante scrivere i test prima di scrivere il codice.Ti costringe a scrivere codice liberamente accoppiato.

Non testare il codice ovviamente funzionante (boilerplate).Quindi, se i tuoi setter e getter sono solo "propertyvalue = value" e "return propertyvalue" non ha senso testarlo.

Anche get / set possono avere strane conseguenze, a seconda di come sono stati implementati, quindi dovrebbero essere trattati come metodi.

Ogni test di questi dovrà specificare set di parametri per le proprietà, definendo proprietà accettabili e inaccettabili per garantire che le chiamate ritornino/falliscano nel modo previsto.

È inoltre necessario essere consapevoli dei trucchi di sicurezza, ad esempio l'iniezione SQL, e testarli.

Quindi sì, devi preoccuparti di testare le proprietà.

Credo che sia sciocco testare getter e setter quando eseguono solo una semplice operazione.Personalmente non scrivo unit test complessi per coprire qualsiasi modello di utilizzo.Cerco di scrivere abbastanza test per assicurarmi di aver gestito il normale comportamento di esecuzione e tutti i casi di errore a cui riesco a pensare.Scriverò più unit test come risposta alle segnalazioni di bug.Utilizzo il test unitario per garantire che il codice soddisfi i requisiti e per facilitare le modifiche future.Mi sento molto più disposto a cambiare il codice quando so che se rompo qualcosa il test fallirà.

Vorrei scrivere un test per tutto ciò per cui stai scrivendo codice che sia testabile al di fuori dell'interfaccia GUI.

In genere, qualsiasi logica che scrivo ha una logica aziendale che inserisco all'interno di un altro livello o livello di logica aziendale.

Quindi scrivere test per tutto ciò che fa qualcosa è facile da fare.

Primo passaggio, scrivi un test unitario per ciascun metodo pubblico nel tuo "Livello di logica aziendale".

Se avessi una lezione come questa:

   public class AccountService
    {
        public void DebitAccount(int accountNumber, double amount)
        {

        }

        public void CreditAccount(int accountNumber, double amount)
        {

        }

        public void CloseAccount(int accountNumber)
        {

        }
    }

La prima cosa che farei prima di scrivere qualsiasi codice sapendo che avevo queste azioni da eseguire sarebbe iniziare a scrivere test unitari.

   [TestFixture]
    public class AccountServiceTests
    {
        [Test]
        public void DebitAccountTest()
        {

        }

        [Test]
        public void CreditAccountTest()
        {

        }

        [Test]
        public void CloseAccountTest()
        {

        }
    }

Scrivi i tuoi test per convalidare il codice che hai scritto per fare qualcosa.Se stai ripetendo una raccolta di cose e modifichi qualcosa su ciascuna di esse, scrivi un test che fa la stessa cosa e asserisci che è realmente accaduto.

Ci sono molti altri approcci che puoi adottare, vale a dire Behavoir Driven Development (BDD), che è più coinvolto e non è un ottimo punto di partenza con le tue capacità di test unitario.

Quindi, la morale della storia è: testare tutto ciò che fa qualcosa di cui potresti essere preoccupato, mantenere i test unitari testando cose specifiche di piccole dimensioni, molti test sono buoni.

Mantieni la tua logica aziendale al di fuori del livello dell'interfaccia utente in modo da poter scrivere facilmente test per loro e sarai bravo.

raccomando TestDriven.Net O ReSharper poiché entrambi si integrano facilmente in Visual Studio.

beh, se pensi che possa rompersi, scrivi un test per verificarlo.Di solito non provo setter/getter, ma diciamo che ne crei uno per User.Name, che concatena nome e cognome, scriverei un test quindi se qualcuno cambia l'ordine per cognome e nome, almeno lo saprebbe ha cambiato qualcosa che era stato testato.

La risposta canonica è "testare tutto ciò che può rompersi". Se sei sicuro che le proprietà non si romperanno, non testarle.

E una volta che si scopre che qualcosa non funziona (trovi un bug), ovviamente significa che devi testarlo.Scrivi un test per riprodurre il bug, guardalo fallire, quindi correggi il bug, quindi guarda il test passare.

Consiglierei di scrivere più test per i metodi di autenticazione e salvataggio.Oltre al caso di successo (dove vengono forniti tutti i parametri, tutto è scritto correttamente, ecc.), è utile effettuare test per vari casi di errore (parametri errati o mancanti, connessioni al database non disponibili, se applicabile, ecc.).raccomando Unit test pragmatico in C# con NUnit come referenza.

Come altri hanno affermato, i test unitari per getter e setter sono eccessivi, a meno che non ci sia una logica condizionale nei tuoi getter e setter.

Sebbene sia possibile indovinare correttamente dove il tuo codice necessita di essere testato, generalmente penso che tu abbia bisogno di metriche per sostenere questa ipotesi.A mio avviso, i test unitari vanno di pari passo con le metriche di copertura del codice.

Codice con molti test ma una piccola copertura non è stato ben testato.Detto questo, anche il codice con una copertura del 100% ma senza testare i limiti e i casi di errore non è eccezionale.

Desideri un equilibrio tra copertura elevata (minimo 90%) e dati di input variabili.

Ricordatevi di verificare la presenza di "garbage in"!

Inoltre, un test unitario non è un test unitario a meno che non controlli un errore.I test unitari che non hanno asserzioni o sono contrassegnati con eccezioni note testeranno semplicemente che il codice non muore quando viene eseguito!

Devi progettare i tuoi test in modo che riportino sempre fallimenti o dati imprevisti/indesiderati!

Rende il nostro codice migliore...periodo!

Una cosa che noi sviluppatori di software dimentichiamo quando facciamo sviluppo basato sui test è lo scopo dietro le nostre azioni.Se uno unit test viene scritto dopo che il codice di produzione è già stato creato, il valore del test diminuisce notevolmente (ma non viene perso completamente).

Nel vero spirito dei test unitari, questi test lo sono non principalmente lì per "testare" più del nostro codice;o per ottenere una copertura del codice migliore del 90% -100%.Questi sono tutti benefici accessori di scrivere prima i test.Il grande vantaggio è che il nostro codice di produzione finirà per essere scritto molto meglio grazie al processo naturale di TDD.

Per aiutare a comunicare meglio questa idea, può essere utile leggere quanto segue:

La teoria imperfetta dei test unitari
Sviluppo software mirato

Se sentiamo che l'atto di scrivere più test unitari è ciò che ci aiuta a ottenere un prodotto di qualità superiore, allora potremmo soffrire di a Culto del carico dello sviluppo guidato dai test.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top