Isso me levou a testes de unidade e me deixou muito feliz
Nós apenas começamos a fazer testes de unidade. Durante muito tempo, sabia que seria bom começar a fazê-lo, mas não fazia ideia de como começar e, mais importante, o que testar.
Em seguida, tivemos que reescrever uma parte importante do código em nosso programa de contabilidade. Essa parte era muito complexa, pois envolvia muitos cenários diferentes. A parte da qual estou falando é um método para pagar faturas de venda e / ou compra já inseridas no sistema contábil.
Só não sabia como começar a codificá-lo, pois havia muitas opções de pagamento diferentes. Uma fatura pode ser de US $ 100, mas o cliente transferiu apenas US $ 99. Talvez você tenha enviado faturas de vendas a um cliente, mas também tenha adquirido desse cliente. Então você o vendeu por US $ 300, mas você comprou por US $ 100. Você pode esperar que seu cliente pague US $ 200 para liquidar o saldo. E se você vendesse por US $ 500, mas o cliente pagasse apenas US $ 250?
Então, eu tinha um problema muito complexo para resolver com muitas possibilidades de que um cenário funcionasse perfeitamente, mas estaria errado em outro tipo de combinação de invocação / pagamento.
Foi aqui que os testes de unidade foram realizados em socorro.
Comecei a escrever (dentro do código de teste) um método para criar uma lista de faturas, tanto para vendas quanto para compras. Então, escrevi um segundo método para criar o pagamento real. Normalmente, um usuário insere essas informações por meio de uma interface do usuário.
Depois, criei o primeiro TestMethod, testando um pagamento muito simples de uma única fatura sem descontos no pagamento. Toda a ação no sistema aconteceria quando um pagamento bancário fosse salvo no banco de dados. Como você pode ver, criei uma fatura, criei um pagamento (uma transação bancária) e salvei a transação no disco. Nas minhas afirmações, coloco quais devem ser os números corretos que terminam na transação bancária e na fatura vinculada. Verifico o número de pagamentos, os valores do pagamento, o valor do desconto e o saldo da fatura após a transação.
Após a execução do teste, eu iria ao banco de dados e verificaria se o que eu esperava estava lá.
Depois que escrevi o teste, comecei a codificar o método de pagamento (parte da classe BankHeader). Na codificação, eu apenas me preocupei com o código para fazer o primeiro teste passar. Ainda não pensei nos outros cenários mais complexos.
Eu executei o primeiro teste, corrigi um pequeno bug até que meu teste passasse.
Então comecei a escrever o segundo teste, desta vez trabalhando com um desconto de pagamento. Depois de escrever o teste, modifiquei o método de pagamento para oferecer suporte a descontos.
Ao testar a correção com um desconto de pagamento, também testei o pagamento simples. Ambos os testes devem passar, é claro.
Depois, trabalhei até os cenários mais complexos.
1) Pense em um novo cenário
2) Escreva um teste para esse cenário
3) Execute esse teste único para ver se passaria
4) Caso contrário, eu depuraria e modificaria o código até que ele passasse.
5) Ao modificar o código, continuei executando todos os testes
Foi assim que consegui criar meu método de pagamento muito complexo. Sem o teste de unidade, eu não sabia como começar a codificar, o problema parecia esmagador. Com o teste, eu poderia começar com um método simples e estendê-lo passo a passo com a garantia de que os cenários mais simples ainda funcionariam.
Tenho certeza de que o uso do teste de unidade me salvou alguns dias (ou semanas) de codificação e garante mais ou menos a correção do meu método.
Se depois pensar em um novo cenário, posso adicioná-lo aos testes para ver se está funcionando ou não. Caso contrário, posso modificar o código, mas ainda assim tenha certeza de que os outros cenários ainda estão funcionando corretamente. Isso economizará dias e dias na fase de manutenção e correção de erros.
Sim, mesmo o código testado ainda pode ter erros se um usuário faz coisas que você não pensou ou o impediu de fazer
Abaixo estão apenas alguns dos testes que criei para testar minha forma de 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);
}