Cela m'a mis dans les tests unitaires et cela m'a rendu très heureux
Nous venons de commencer à faire des tests unitaires. Pendant longtemps, je savais que ce serait bien de commencer à le faire mais je ne savais pas par où commencer et surtout quoi tester.
Ensuite, nous avons dû réécrire un élément de code important dans notre programme de comptabilité. Cette partie était très complexe car elle impliquait de nombreux scénarios différents. La partie dont je parle est une méthode pour payer les factures de vente et / ou d'achat déjà saisies dans le système comptable.
Je ne savais tout simplement pas comment commencer à le coder, car il y avait tellement d'options de paiement différentes. Une facture peut être de 100 $, mais le client n'a transféré que 99 $. Vous avez peut-être envoyé des factures de vente à un client, mais vous avez également acheté auprès de ce client. Alors vous l'avez vendu pour 300 $ mais vous l'avez acheté pour 100 $. Vous pouvez vous attendre à ce que votre client vous paie 200 $ pour régler le solde. Et si vous vendiez 500 $ mais que le client ne vous paie que 250 $?
J'avais donc un problème très complexe à résoudre avec de nombreuses possibilités qu'un scénario fonctionnerait parfaitement mais serait erroné sur un autre type de combinaison invocie / paiement.
C'est là que les tests unitaires sont venus à la rescousse.
J'ai commencé à écrire (à l'intérieur du code de test) une méthode pour créer une liste de factures, à la fois pour les ventes et les achats. Ensuite, j'ai écrit une deuxième méthode pour créer le paiement réel. Normalement, un utilisateur saisit ces informations via une interface utilisateur.
Ensuite, j'ai créé la première TestMethod, testant un paiement très simple d'une seule facture sans aucune remise de paiement. Toutes les actions du système se produiraient lorsqu'un paiement bancaire serait enregistré dans la base de données. Comme vous pouvez le voir, j'ai créé une facture, créé un paiement (une transaction bancaire) et enregistré la transaction sur le disque. Dans mes affirmations, je mets quels devraient être les bons numéros se retrouvant dans la transaction bancaire et dans la facture liée. Je vérifie le nombre de paiements, les montants des paiements, le montant de la remise et le solde de la facture après la transaction.
Une fois le test exécuté, j'irais dans la base de données et vérifierais si ce à quoi je m'attendais était là.
Après avoir écrit le test, j'ai commencé à coder le mode de paiement (qui fait partie de la classe BankHeader). Dans le codage, je ne me suis préoccupé que du code pour passer le premier test. Je n'ai pas encore pensé aux autres scénarios, plus complexes.
J'ai exécuté le premier test, corrigé un petit bogue jusqu'à ce que mon test réussisse.
Puis j'ai commencé à écrire le deuxième test, cette fois en travaillant avec une remise de paiement. Après avoir effectué le test, j'ai modifié le mode de paiement pour prendre en charge les remises.
En testant l'exactitude avec une remise de paiement, j'ai également testé le paiement simple. Les deux tests devraient bien sûr réussir.
Ensuite, je suis descendu vers les scénarios les plus complexes.
1) Pensez à un nouveau scénario
2) Ecrire un test pour ce scénario
3) Exécutez ce test unique pour voir s'il réussirait
4) Si ce n'était pas le cas, je déboguerais et modifierais le code jusqu'à ce qu'il passe.
5) Tout en modifiant le code, j'ai continué à exécuter tous les tests
C'est ainsi que j'ai réussi à créer mon moyen de paiement très complexe. Sans test unitaire, je ne savais pas comment commencer à coder, le problème semblait écrasant. Avec les tests, je pourrais commencer avec une méthode simple et l'étendre étape par étape avec l'assurance que les scénarios les plus simples fonctionneraient toujours.
Je suis sûr que l'utilisation des tests unitaires m'a fait gagner quelques jours (ou semaines) de codage et garantit plus ou moins l'exactitude de ma méthode.
Si je pense plus tard à un nouveau scénario, je peux simplement l'ajouter aux tests pour voir s'il fonctionne ou non. Sinon, je peux modifier le code mais toujours être sûr que les autres scénarios fonctionnent toujours correctement. Cela permettra d'économiser des jours et des jours dans la phase de maintenance et de correction des bogues.
Oui, même le code testé peut toujours avoir des bogues si un utilisateur fait des choses auxquelles vous n'avez pas pensé ou l'a empêché de faire
Voici quelques-uns des tests que j'ai créés pour tester mon mode de paiement.
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);
}