Це змусило мене пройти тестування, і це мене дуже тішило
Ми тільки почали робити тестування одиниць. Довгий час я знав, що було б добре почати це робити, але я не мав ідеї, як почати, і що ще важливіше, що тестувати.
Тоді нам довелося переписати важливий фрагмент коду в нашій програмі обліку. Ця частина була дуже складною, оскільки передбачала безліч різних сценаріїв. Частина, про яку я говорю, - це метод оплати продажів та / або придбання рахунків-фактур, вже внесених до бухгалтерської системи.
Я просто не знав, як почати його кодувати, оскільки було так багато різних варіантів оплати. Рахунок-фактура може становити 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);
}