Это привело меня к модульному тестированию и очень обрадовало
Мы только начали проводить модульное тестирование. Долгое время я знал, что было бы хорошо начать этим заниматься, но я понятия не имел, с чего начать и, что более важно, что тестировать.
Затем нам пришлось переписать важный фрагмент кода нашей бухгалтерской программы. Эта часть была очень сложной, так как предполагала множество различных сценариев. Речь идет о методе оплаты счетов-фактур продаж и / или покупок, уже введенных в систему бухгалтерского учета.
Я просто не знал, с чего начать, так как вариантов оплаты было очень много. Счет-фактура может составлять 100 долларов, но клиент перевел только 99 долларов. Возможно, вы отправили счета-фактуры клиенту, но вы также совершили покупку у этого клиента. Итак, вы продали его за 300 долларов, а купили за 100 долларов. Вы можете ожидать, что ваш клиент заплатит вам 200 долларов для погашения баланса. А что, если вы продали за 500 долларов, а покупатель заплатит вам всего 250 долларов?
Таким образом, у меня была очень сложная проблема, которую нужно было решить, с множеством возможностей, что один сценарий будет работать идеально, но будет неправильным для другого типа комбинации счет / платеж.
Здесь на помощь пришло модульное тестирование.
Я начал писать (внутри тестового кода) метод создания списка счетов-фактур, как для продаж, так и для покупок. Затем я написал второй способ создания фактического платежа. Обычно пользователь вводит эту информацию через пользовательский интерфейс.
Затем я создал первый TestMethod, тестируя очень простую оплату одного счета без каких-либо скидок при оплате. Все действия в системе будут происходить, когда банковский платеж будет сохранен в базе данных. Как видите, я создал счет, создал платеж (банковскую транзакцию) и сохранил транзакцию на диск. В своих утверждениях я указываю правильные числа, которые должны отображаться в банковской транзакции и в связанном счете-фактуре. Я проверяю количество платежей, суммы платежей, размер скидки и остаток счета после транзакции.
После запуска теста я заходил в базу данных и дважды проверял, было ли там то, что я ожидал.
После того, как я написал тест, я начал программировать способ оплаты (часть класса BankHeader). При кодировании я беспокоился только о коде, чтобы пройти первый тест. Я еще не думал о других, более сложных сценариях.
Я провел первый тест, исправил небольшую ошибку, пока мой тест не прошел.
Затем я начал писать второй тест, на этот раз работая со скидкой при оплате. Написав тест, я изменил способ оплаты для поддержки скидок.
При тестировании на корректность со скидкой при оплате я также протестировал простой платеж. Разумеется, оба теста должны пройти.
Затем я перешел к более сложным сценариям.
1) Придумайте новый сценарий
2) Напишите тест для этого сценария
3) Запустите этот единственный тест, чтобы узнать, пройдет ли он
4) В противном случае я бы отлаживал и изменял код, пока он не прошел.
5) При изменении кода я продолжал запускать все тесты
Так мне удалось создать свой очень сложный способ оплаты. Без модульного тестирования я не знал, как начать кодить, проблема казалась огромной. При тестировании я мог начать с простого метода и шаг за шагом расширять его с уверенностью, что более простые сценарии будут работать.
Я уверен, что использование модульного тестирования сэкономило мне несколько дней (или недель) программирования и более или менее гарантирует правильность моего метода.
Если позже я подумаю о новом сценарии, я могу просто добавить его в тесты, чтобы посмотреть, работает он или нет. В противном случае я могу изменить код, но все же убедиться, что другие сценарии все еще работают правильно. Это сэкономит дни и дни на этапе обслуживания и исправления ошибок.
Да, даже в протестированном коде могут быть ошибки, если пользователь делает то, о чем вы не задумывались или не позволял ему делать.
Ниже приведены лишь некоторые из тестов, которые я создал для проверки моего метода оплаты.
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);
}