Questo mi ha portato a test unitari e mi ha fatto molto piacere
Abbiamo appena iniziato a fare test di unità. Per molto tempo ho saputo che sarebbe stato bello iniziare a farlo, ma non avevo idea di come iniziare e, cosa più importante, cosa testare.
Quindi abbiamo dovuto riscrivere un codice importante nel nostro programma di contabilità. Questa parte è stata molto complessa in quanto ha coinvolto molti scenari diversi. La parte di cui sto parlando è un metodo per pagare le vendite e / o acquistare fatture già inserite nel sistema contabile.
Non sapevo come iniziare a codificarlo, poiché c'erano così tante diverse opzioni di pagamento. Una fattura potrebbe essere $ 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 l'hai venduto per $ 300 ma hai comprato per $ 100. Puoi aspettarti che il tuo cliente ti paghi $ 200 per saldare il saldo. E se vendessi per $ 500 ma il cliente ti pagasse solo $ 250?
Quindi ho avuto un problema molto complesso da risolvere con molte possibilità che uno scenario funzionasse perfettamente ma sarebbe sbagliato su un altro tipo di combinazione invocie / pagamento.
È qui che i test unitari sono venuti in soccorso.
Ho iniziato a scrivere (all'interno del codice di prova) un metodo per creare un elenco di fatture, sia per le vendite che per gli acquisti. Quindi ho scritto un secondo metodo per creare il pagamento effettivo. Normalmente un utente inserisce tali informazioni tramite un'interfaccia utente.
Quindi ho creato il primo TestMethod, testando un pagamento molto semplice di una singola fattura senza sconti di pagamento. Tutte le azioni nel sistema si verificherebbero quando un pagamento bancario viene 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 del pagamento, l'importo dello sconto e il saldo della fattura dopo la transazione.
Dopo l'esecuzione del test, andrei nel database e ricontrollerei se quello che mi aspettavo fosse lì.
Dopo aver scritto il test, ho iniziato a codificare il metodo di pagamento (parte della classe BankHeader). Nella codifica mi sono solo preoccupato del codice per eseguire il primo test. Non pensavo ancora agli altri scenari più complessi.
Ho eseguito il primo test, risolto un piccolo bug fino a quando il mio test sarebbe passato.
Quindi 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 la verifica della correttezza con uno sconto sul pagamento, ho anche testato il pagamento semplice. Entrambi i test dovrebbero passare ovviamente.
Poi sono arrivato 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 sarebbe passato
4) In caso contrario eseguirò il debug e modificherei il codice fino a quando non passerà.
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 la codifica, 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 continuerebbero a funzionare.
Sono sicuro che l'uso del test unitario mi ha salvato 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 no. Altrimenti posso modificare il codice ma essere sicuro che gli altri scenari funzionino ancora correttamente. Ciò consentirà di risparmiare giorni e giorni nella fase di manutenzione e correzione degli errori.
Sì, anche il codice testato può avere ancora dei bug se un utente fa cose a cui non hai pensato o che gli ha 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);
}