Як ви знаєте, що перевірити під час написання одиничних тестів? [зачинено]


127

Використовуючи C #, мені потрібен клас, який називається, Userякий має ім’я користувача, пароль, активний прапор, ім’я, прізвище, повне ім’я тощо.

Повинні існувати методи аутентифікації та збереження користувача. Я просто пишу тест на методи? І чи потрібно мені навіть хвилюватися про тестування властивостей, оскільки вони є.


Ця публікація допоможе звузити ширше запитання: earnestengineer.blogspot.com/2018/03/… Ви можете скористатися цими вказівками, щоб зосередити своє запитання
Lindsay Morsillo

Пам’ятайте, що паролі не повинні зберігатися як простий текст.
Містер Андерсон

Відповіді:


131

Багато чудових відповідей на це також є на моє запитання: " Початок TDD - виклики? Рішення? Рекомендації? "

Можна також порекомендувати переглянути мій пост у блозі (який частково надихнувся моїм запитанням), у мене є хороші відгуки про це. А саме:

Я не знаю, з чого почати?

  • Почніть знову. Думайте про написання тестів лише тоді, коли ви пишете новий код. Це може бути переробка старого коду або абсолютно нова функція.
  • Почати просто. Не бігайте і не намагайтеся обернути тестувальну основу, а також TDD-esque. Налагодження працює чудово. Використовуйте його як вихідну точку. Це не возиться з вашим проектом і не створює залежностей.
  • Почніть позитивно. Ви намагаєтеся вдосконалити своє ремесло, добре почуваєтесь у ньому. Я бачив безліч розробників, які із задоволенням застоюються і не намагаються нові речі покращити себе. Ви робите правильно, пам’ятайте про це, і це допоможе вам відмовитися від здачі.
  • Почніть готові до виклику. Починати тестування досить важко. Очікуйте виклик, але пам’ятайте - виклики можна подолати.

Тільки тест на те, що ви очікуєте

У мене були справжні проблеми, коли я вперше почав, тому що постійно сидів там, намагаючись з’ясувати всі можливі проблеми, які могли виникнути, а потім намагався перевірити її та виправити. Це швидкий шлях до головного болю. Тестування має бути справжнім процесом YAGNI. Якщо ви знаєте, що є проблема, то напишіть її на тест. Інакше не турбуйтеся.

Тільки тест на одну річ

Кожен тестовий випадок повинен коли-небудь перевіряти одне. Якщо ви коли-небудь опинитесь як "і" у назві тестового випадку, ви щось робите не так.

Я сподіваюся, що це означає, що ми можемо перейти від "геттерів та сетерів" :)


2
"Якщо ви знаєте, що є проблема, тоді напишіть тест на це. Інакше не турбуйтеся." Я б не погоджувався з тим, як це написано. У мене склалося враження, що одиничні тести повинні охоплювати всі можливі шляхи виконання.
Корін Блейкі

3
Хоча деякі можуть виступати за такі речі, я особисто цього не роблю. Добрі 90% мого головного болю виникли від спроби зробити "все". Я кажу тест на те, що ви очікуєте, що трапиться (щоб ви знали, що отримуєте правильні значення), але не намагайтеся все зрозуміти. ЯГНІ.
Роб Купер

4
Я також виступаю за підхід "перевірити ваші помилки". Якби всі ми мали нескінченний час і терпіння, ми перевірили б кожен можливий шлях виконання. Але ми цього не робимо, тому вам доведеться витратити зусилля там, де це дасть найбільший ефект.
Шверн

63

Перевірте свій код, а не мову.

Тест одиниці типу:

Integer i = new Integer(7);
assert (i.instanceOf(integer));

корисно лише, якщо ви пишете компілятор і є ненульовий шанс, що ваш instanceofметод не працює.

Не перевіряйте матеріали, на які ви можете покластися на мову, яку потрібно застосувати. У вашому випадку я б зосередився на ваших методах аутентифікації та збереження - і я писав би тести, щоб переконатися, що вони зможуть граціозно виконувати нульові значення в будь-якому або всіх цих полях.


1
Хороший пункт про "Не тестуйте рамки" - Щось я натрапив також на новинку. + 1'ed :)
Роб Купер

38

Це змусило мене пройти тестування, і це мене дуже тішило

Ми тільки почали робити тестування одиниць. Довгий час я знав, що було б добре почати це робити, але я не мав ідеї, як почати, і що ще важливіше, що тестувати.

Тоді нам довелося переписати важливий фрагмент коду в нашій програмі обліку. Ця частина була дуже складною, оскільки передбачала безліч різних сценаріїв. Частина, про яку я говорю, - це метод оплати продажів та / або придбання рахунків-фактур, вже внесених до бухгалтерської системи.

Я просто не знав, як почати його кодувати, оскільки було так багато різних варіантів оплати. Рахунок-фактура може становити 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);
    }

1
У вашому тесті знайдено помилку! Ви повторите цей рядок, замість того, щоб включити 2 в один з них:Assert.AreEqual(0, bankHeader.BankCashDetails[0].Payments[3].InvoiceHeader.Balance);
Райан Пешель

2
Ви кажете: «Після тестування я зайшов до бази даних і ще раз перевірив, чи там я очікував». Це хороший приклад інтеграційного тесту між компонентами вашої системи - не ізольований тест одиничного коду.
JTech

2
Ви також порушили правило про більш ніж один засіб на тест.
Стів

13

Якщо вони дійсно тривіальні, то не турбуйтеся про тестування. Наприклад, якщо вони реалізовані так;

public class User
{
    public string Username { get; set; }
    public string Password { get; set; }
}

Якщо, з іншого боку, ви робите щось розумне (наприклад, шифрування та розшифрування пароля в геттері / сетері), тоді дайте йому тест.


10

Правило полягає в тому, що ви повинні перевірити кожну написану вами логіку. Якщо ви реалізували якусь конкретну функціональність в геттерах і сетерах, я думаю, що вони варті тестування. Якщо вони присвоюють значення лише деяким приватним полям, не турбуйтеся.


6

Це питання, здається, є питанням, де можна провести межу того, які методи тестуються, а які ні.

Встановлювачі та геттери для присвоєння вартості були створені з урахуванням послідовності та майбутнього зростання, передбачаючи, що деякий час вниз дорога сеттер / геттер може перетворитися на більш складні операції. Було б доцільно встановити одиничні тести цих методів, також заради послідовності та подальшого зростання.

Надійність коду, особливо під час змін, щоб додати додаткову функціональність, є основною метою. Мені невідомо, що хтось колись звільняється за включення сетерів / геттерів у методологію тестування, але я впевнений, що є люди, які хотіли б, щоб вони протестували методи, які останнім часом вони знали, або можуть згадати, були простими комплектами / отримання обгортки, але це не було довше справа.

Можливо, інший член команди розширив набір методів set / get, щоб включити логіку, яку зараз потрібно перевірити, але потім не створив тести. Але тепер ваш код викликає ці методи, і ви не знаєте, що вони змінилися і потребують поглибленого тестування, а тестування, яке ви робите в процесі розробки та QA, не викликає дефект, але реальні бізнес-дані на перший день випуску роблять запустити його.

Двоє товаришів по команді тепер будуть обговорювати питання про те, хто кинув м'яч та не зміг поставити тести на одиницю, коли набір / потрапляє в моду, включаючи логіку, яка може вийти з ладу, але не покривається одиничним тестом. Командному товаришеві, який спочатку написав набір / отримує, буде легше виходити з цього чистого, якщо тести будуть реалізовані з першого дня на простому наборі / отриманні.

На мою думку, кілька хвилин «витраченого» часу на покриття ВСІХ методів одиничними тестами, навіть тривіальними, можуть врятувати дні головного болю в дорозі та втрати грошей / репутації бізнесу та втрати чиєїсь роботи.

І той факт, що ви обробляли тривіальні методи з одиничними тестами, може помітити той молодший товариш по команді, коли вони поміняють тривіальні методи на нетривіальні та запропонують їм оновити тест, і тепер ніхто не переживає проблем, тому що дефект містився від досягнення виробництва.

Те, як ми кодуємо, та дисципліна, яку видно з нашого коду, можуть допомогти іншим.


4

Ще одна канонічна відповідь. Це, я вважаю, від Рона Джефріса:

Випробуйте лише код, який ви хочете працювати.


3

Тестування кодового котла - це марна трата часу, але, як каже Славо, якщо ви додасте побічний ефект до своїх геттерів / сеттерів, то вам слід написати тест, який супроводжує цю функціональність.

Якщо ви займаєтеся тестовою розробкою, спочатку слід написати контракт (наприклад, інтерфейс), а потім написати тест (и), щоб виконати цей інтерфейс, який документує очікувані результати / поведінку. Потім запишіть свої методи самі, не торкаючись коду у ваших модульних тестах. Нарешті, візьміть інструмент для покриття коду та переконайтесь, що ваші тести виконують усі логічні шляхи у вашому коді.


3

Дійсно тривіальний код, як, наприклад, геттери та сетери, які не мають додаткової поведінки, ніж встановлення приватного поля, є надмірними для тестування. У 3.0 C # навіть є синтаксичний цукор, де компілятор піклується про приватне поле, тому вам не доведеться програмувати це.

Зазвичай я пишу багато дуже простих тестів, що підтверджують поведінку, яку я очікую від своїх занять. Навіть якщо це прості речі, такі як додавання двох чисел. Я багато перемикаюся між написанням простого тесту і написанням деяких рядків коду. Причиною цього є те, що я потім можу змінювати код, не боячись, що я зламав речі, про які не думав.


Радий, що ви добре позначили принцип KISS. У мене часто є тести, які буквально схожі на 2-3 рядки коду, справжні маленькі, прості тести. Легко громити і важко зламати :) + 1'ed
Роб Купер

3

Ви повинні все перевірити. Зараз у вас є геттери і сетери, але одного дня ви можете дещо змінити їх, можливо, зробити перевірку чи щось інше. Тести, які ви пишете сьогодні, будуть використані завтра, щоб переконатися, що все продовжує працювати, як завжди. Коли ви пишете тест, ви повинні забути такі міркування, як "зараз це банально". У спритному або тестовому контексті ви повинні перевірити, припускаючи майбутнє рефакторинг. Крім того, чи намагалися ви вводити дійсно дивні значення, такі як надзвичайно довгі рядки чи інший "поганий" вміст? Ну, ви повинні ... ніколи не припускайте, наскільки погано ваш код може зловживати в майбутньому.

Взагалі я вважаю, що написання обширних тестів користувачів з одного боку, виснажливе. З іншого боку, хоча це завжди дає вам неоціненну інформацію про те, як має працювати ваша програма, і допомагає вам викинути легкі (і помилкові) припущення (наприклад: ім’я користувача завжди буде менше 1000 символів).


3

Для простих модулів, які можуть опинитися в наборі інструментів або у проекті з відкритим кодом, ви повинні протестувати якомога більше, включаючи тривіальні геттери та сетери. Що ви хочете пам’ятати, це те, що формувати одиничний тест під час написання певного модуля досить просто і прямо вперед. Додавання геттерів та сетерів - мінімальний код, з яким можна обробляти без особливих роздумів. Однак, як тільки ваш код розміщений у більшій системі, це додаткове зусилля може захистити вас від змін базової системи, таких як зміни типу базового класу. Тестування вічі - найкращий спосіб повного регресу.


2

Не завадить писати одиничні тести для ваших жителів та сеттерів. Наразі вони можуть просто робити поле get / sets під кришкою, але в майбутньому у вас може бути логіка перевірки або залежність між властивостями, які потрібно перевірити. Простіше писати це зараз, поки ти думаєш про це, а потім пам'ятаєш доопрацювати його, якщо цей час коли-небудь настане.


Добре, якщо вашим геттерам / сетерам потрібні одиничні тести, має бути певна логіка, пов’язана з ними, так що це означає, що логіка повинна бути записана всередині них, якщо вони не мають логіки, не потрібно писати одиничні тести.
Поп Каталін

2
Його сенс полягає в тому, що логіка може бути додана до них пізніше.
LegendLength

2

загалом, коли метод визначений лише для певних значень, перевіряйте значення на межі та за межею того, що є прийнятним. Іншими словами, переконайтеся, що ваш метод робить те, що йому належить зробити, але більше нічого . Це важливо, тому що, коли ви збираєтеся зазнати невдачі, ви хочете провалитися рано.

У ієрархіях спадкування обов'язково перевіряйте відповідність LSP .

Тестування замовчувачів та сетерів не здається мені дуже корисним, якщо ви не плануєте пізніше провести перевірку.


2

добре, якщо ви думаєте, що це може зламатися, напишіть на це тест. Я, як правило, не тестую сетер / геттер, але дозволяє сказати, що ви зробите для User.Name, які об'єднують ім'я та прізвище, я би написав тест, тому якщо хтось змінить порядок на прізвище та ім'я, принаймні він би знав він змінив щось тестоване.


2

Канонічна відповідь - "перевірити все, що може зламати". Якщо ви впевнені, що властивості не порушаться, не перевіряйте їх.

І коли щось виявляється, що зламалося (ви виявили помилку), очевидно, це означає, що вам потрібно перевірити це. Напишіть тест, щоб відтворити помилку, спостерігайте за її відмовою, потім виправляйте помилку, а потім дивіться тестовий пропуск.


1

Як я розумію одиничні тести в контексті спритного розвитку, Майку, так, вам потрібно протестувати геттери та сетери (якщо вважати, що вони є загальнодоступними). Вся концепція одиничного тестування полягає в тестуванні програмного блоку, який в даному випадку є класом, як чорного поля . Оскільки геттери та сетери є видимими зовні, вам потрібно перевірити їх разом із службою автентифікації та збереження.


1

Якщо методи автентифікації та збереження використовують властивості, то ваші тести будуть побічно торкатися властивостей. Поки властивості лише забезпечують доступ до даних, то явне тестування не повинно бути необхідним (якщо ви не збираєтесь на 100% охоплення).


1

Я б протестував ваші геттери та сетери. Залежно від того, хто пише код, деякі люди змінюють значення методів getter / setter. Я бачив ініціалізацію змінних та інші перевірки як частину методів отримання. Щоб перевірити подібні речі, ви хочете одиничні тести, які чітко покривають цей код.


1

Особисто я б "перевірив все, що може зламатися", і простий геттер (або ще краще автоматичні властивості) не зламається. У мене ніколи не було простої заяви про повернення, і тому ніколи не маю на них тесту. Якщо в геттерів є розрахунок всередині них чи інша форма тверджень, я, безумовно, додав би тести для них.

Особисто я використовую Moq як макетну структуру об'єкта, а потім перевіряю, чи мій об'єкт називає навколишні об'єкти так, як слід.


1

Ви повинні покрити виконання кожного методу класу за допомогою UT та перевірити повернення значення методу. Сюди входять геттери та сетери, особливо у випадку, якщо члени (властивості) є складними класами, що вимагає великого розподілу пам'яті під час їх ініціалізації. Зателефонуйте до сетера, наприклад, дуже великим рядком (або з грецькими символами) і перевірте, чи результат правильний (не усічений, кодування добре тощо)

У випадку простих цілих чисел, що також застосовується - що станеться, якщо ви пройдете довге замість цілого числа? Ось чому ви пишете UT для :)


1

Я б не перевіряв фактичні настройки властивостей. Мене б більше хвилювало питання, як ці властивості заповнюються споживачем і чим він їх заселяє. При будь-якому тестуванні ви повинні зважувати ризики з часом / вартістю тестування.


1

Ви повинні протестувати "кожен нетривіальний блок коду", використовуючи одиничні тести, наскільки це можливо.

Якщо ваші властивості тривіальні і малоймовірно, що хтось введе в неї помилку, тоді не слід перевіряти їх.

Ваші методи Authenticate () та Save () виглядають як хороші кандидати для тестування.


1

В ідеалі, ви б робили одиничні тести, як ви писали клас. Це те, як ви мали намір зробити це під час використання тестово керованої розробки. Ви додаєте тести під час реалізації кожної функції функції, переконуючись, що ви також покриваєте крайові регістри тестом.

Складання тестів після цього набагато болючіше, але доцільно.

Ось що я зробив би на вашій посаді:

  1. Напишіть базовий набір тестів, які перевіряють основну функцію.
  2. Отримайте NCover і запустіть його на своїх тестах. Ваш тест покриття, ймовірно, буде приблизно 50% в цей момент.
  3. Продовжуйте додавати тести, які охоплюють ваші крайові справи, поки ви не отримаєте покриття приблизно на 80% -90%

Це повинно дати вам хороший робочий набір одиничних тестів, які будуть діяти як хороший буфер проти регресій.

Єдина проблема такого підходу полягає в тому, що код повинен бути розроблений для перевірки таким чином. Якщо ви зробили якісь помилки при з'єднанні на початку, ви не зможете отримати дуже високе покриття дуже легко.

Ось чому дуже важливо написати тести, перш ніж писати код. Це змушує вас писати код, який вільно поєднаний.


1

Не перевіряйте явно працюючий (котловий) код. Отже, якщо ваші налаштування та користувачі отримують лише "valuevalue = value" і "return propertyvalue", тестувати це не має сенсу.


1

Навіть отримання / встановлення може мати незвичайні наслідки, залежно від того, як вони були реалізовані, тому до них слід ставитися як до методів.

У кожному тесті потрібно буде вказати набори параметрів для властивостей, визначаючи як прийнятні, так і неприйнятні властивості для забезпечення повернення / відмови викликів очікуваним чином.

Вам також потрібно знати про безпеку, як приклад введення SQL, і перевірити їх.

Так що так, вам потрібно потурбуватися про тестування властивостей.


1

Я вважаю, що нерозумно перевіряти геттери та сетери, коли вони роблять лише просту операцію. Особисто я не пишу складні одиничні тести для покриття будь-якої моделі використання. Я намагаюсь написати достатньо тестів, щоб переконатися, що я впорався з нормальною поведінкою виконання та якомога більше випадків помилок я можу придумати. Я напишу більше одиничних тестів як відповідь на звіти про помилки. Я використовую тестовий блок, щоб переконатися, що код відповідає вимогам та щоб спростити подальшу модифікацію. Я відчуваю набагато більше бажання змінити код, коли знаю, що якщо щось порушу, тест не вдасться.


1

Я б написав тест на все, для чого ви пишете код, який можна перевірити поза інтерфейсом GUI.

Як правило, будь-яку логіку, яку я пишу, яка має будь-яку логіку бізнесу, я розміщую всередині іншого рівня або рівня бізнес-логіки.

Тоді писати тести на все, що щось робить, легко зробити.

Спочатку пройдіть, напишіть одиничний тест для кожного загальнодоступного методу у вашому "Бізнес-логічний шар".

Якби у мене був такий клас:

   public class AccountService
    {
        public void DebitAccount(int accountNumber, double amount)
        {

        }

        public void CreditAccount(int accountNumber, double amount)
        {

        }

        public void CloseAccount(int accountNumber)
        {

        }
    }

Перше, що я зробив би, перш ніж писати будь-який код, знаючи, що я повинен виконувати ці дії, - це почати писати одиничні тести.

   [TestFixture]
    public class AccountServiceTests
    {
        [Test]
        public void DebitAccountTest()
        {

        }

        [Test]
        public void CreditAccountTest()
        {

        }

        [Test]
        public void CloseAccountTest()
        {

        }
    }

Напишіть свої тести, щоб перевірити код, який ви написали, щоб зробити щось. Якщо ви повторюєте колекцію речей і щось змінюєте про кожну з них, напишіть тест, який робить те саме, і затвердіть те, що відбулося насправді.

Ви можете скористатись багатьма іншими підходами, а саме Behavoir Driven Development (BDD), це більше стосується і не чудове місце, щоб почати з ваших навичок тестування одиниць.

Отже, мораль історії полягає в тому, щоб перевірити все, що робить все, що вас може турбувати, продовжуйте перевіряти одиничні тести на конкретні речі, які мають невеликі розміри, багато тестів хороші.

Тримайте свою бізнес-логіку поза шаром «Інтерфейс користувача», щоб ви могли легко писати тести для них, і ви будете добрі.

Я рекомендую TestDriven.Net або ReSharper, оскільки вони легко інтегруються у Visual Studio.


1

Я рекомендую написати кілька тестів для методів аутентифікації та збереження. Окрім випадку успіху (де надані всі параметри, все правильно написано тощо), добре провести тести на різні випадки відмови (неправильні або відсутні параметри, недоступні підключення до бази даних, якщо це застосовується тощо). Я рекомендую прагматичне тестування одиниць в C # за допомогою NUnit як орієнтир.

Як заявили інші, одиничні тести для геттерів і сеттерів є надмірними, якщо тільки у ваших геттерів та сеттерів немає умовної логіки.


1

Хоча можна правильно здогадатися, де потрібен тестування вашого коду, я, як правило, вважаю, що вам потрібні показники для резервного копіювання цього здогаду. Тестування одиниць, на мій погляд, йде рука об руку з показниками покриття кодом.

Код з великою кількістю тестів, але невелике покриття недостатньо перевірено. Однак, код зі 100% охопленням, але не тестування випадків меж та помилок, також не є великим.

Ви хочете отримати баланс між високим покриттям (мінімум 90%) та змінними вхідними даними.

Не забудьте перевірити на "сміття в"!

Крім того, тест на одиницю не є одиничним тестом, якщо він не перевіряє на предмет відмови. Блок-тести, які не мають тверджень або позначені відомими винятками, просто перевірять, що код не загине при запуску!

Вам потрібно спроектувати свої тести так, щоб вони завжди повідомляли про помилки або несподівані / небажані дані!


1

Це робить наш код кращим ... період!

Одне, про що розробники програмного забезпечення забувають, коли роблять тестові розробки, - це мета наших дій. Якщо одиничний тест пишеться після того, як виробничий код вже встановлений, значення тесту знижується (але повністю не втрачається).

В істинному дусі для модульного тестування, ці тести НЕ в першу чергу там , щоб «тест» більше нашого коду; або щоб отримати 90% -100% кращого покриття коду. Це все переваги, перш ніж написати тести. Велика користь полягає в тому, що наші виробничі коди можуть бути написані набагато краще завдяки природному процесу TDD.

Щоб краще повідомити цю ідею, у читанні може бути корисним:

Неправильна теорія одиничних тестів
Цілеспрямована розробка програмного забезпечення

Якщо ми відчуваємо, що акт написання більше одиничних тестів - це те, що допомагає нам отримати продукт більш високої якості, то ми можемо страждати від вантажного культу розвитку тестових механізмів.


Я не згоден із твердженням, що одиничні тести не мають значення після того, як виробничий код вже діє. Такі твердження не враховують їх корисність для відтворення умов помилок, виявлених у виробництві, або в розумінні коду, успадкованого від попереднього розробника чи команди.
Скотт Лоуренс

Я, можливо, зіткнувся неправильно. Я не мав на увазі, що одиничні тести не мають значення після створення коду. Однак їх цінність знижується. Найбільша користь для одиничного тестування отримує від властивої магії, яка виникає, коли ми дозволяємо їм рухати наше виробництво.
Скотт Саад
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.