TDD з шаблоном сховища


10

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

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

Я думаю про це вже два дні, і досі не можу придумати жодного розумного рішення. Що мені робити?

Відповіді:


11

Що репозиторій робить, це перекласти з вашого домену на вашу базу даних DAL, наприклад, NHibernate або Doctrine, або ваші класи, що виконують SQL. Це означає, що ваш сховище буде викликати методи у зазначеній рамці для виконання своїх обов'язків: ваше сховище будує запити, необхідні для отримання даних. Якщо ви не використовуєте структуру ORM (сподіваюся, що ви є ...), сховище було б місцем, де будуються необроблені SQL-заяви.

Найбільш основним із цих методів є збереження: у більшості випадків це просто передасть об’єкт із сховища на блок роботи (або сеанс).

public void Save(Car car)
{
    session.Save(car);
}

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

public function GetCarWithId(String id)
{
    return Session.QueryOver<Car>()
                    .Where(x => x.Id == id)
                    .SingleOrDefault();
}

Все ще не надто складно, але ви можете уявити собі з численними умовами (дозвольте мені всі машини, зроблені після 2010 року для всіх марок групи "Фольксваген") це стає складним. Тож у справжній моди TDD вам потрібно це перевірити. Існує кілька способів зробити це.

Варіант 1: Знущаються над дзвінками до системи ORM

Звичайно, ви можете знущатися над об'єктом Session і просто стверджувати, що правильні дзвінки зроблені. Хоча це тестує сховище, воно насправді не тестово , тому що ви просто тестуєте, що сховище всередині виглядає так, як вам потрібно. В основному тест говорить, що "код повинен виглядати так". Тим не менш, це правильний підхід, але, здається, такий вид тесту має дуже мало значення.

Варіант 2: (Пере) побудувати базу даних з тестів

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

Варіант 3: Тест на фактичній базі даних

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

Не тестуйте DAL

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

Під час тестування повернення ваших сховищ ви можете просто перевірити, чи збігається якесь ідентифікаційне властивість об’єкта вашого домену. Це може бути ідентифікатором, але в тестах часто корисніше перевірити читабельність людини. У "дістань мені всі машини, зроблені після 2010 року ....", це може просто перевірити, чи повернуто п'ять машин, а номерні знаки "вставте сюди список". Додатковою перевагою є те, що воно змушує задуматися про сортування, і ваш тест автоматично змушує сортувати. Ви здивуєтеся, скільки програм або сортують декілька разів (поверніть відсортовану з бази даних, сортуйте перед створенням об’єкта перегляду, а потім сортуйте об’єкт перегляду, все на тій самій властивості на всякий випадок ) або неявно припустите сортування сховища та випадково видаліть які були по дорозі, порушуючи інтерфейс користувача.

"Одиничний тест" - це лише назва

На мою думку, одиничні тести здебільшого не повинні потрапляти в базу даних. Ви будуєте додаток так, що кожен фрагмент коду, який потребує даних з джерела, робить це з сховищем, і це сховище вводиться як залежність. Це дозволяє легко глузувати і всі TDD-добрі ви хочете. Але врешті-решт, ви хочете переконатися, що ваші сховища виконують свої обов'язки, і якщо найпростіший спосіб це зробити, це потрапити в базу даних, так і нехай буде. Я давно відпустив думку про те, що "одиничні тести не повинні торкатися бази даних", і я зрозумів, що для цього є дуже реальні причини. Але лише в тому випадку, якщо ви можете зробити це автоматично і повторно. І погода, яку ми називаємо таким тестом, «одиничне випробування» або «тест на інтеграцію» - суперечка.


3
Тести блоку та тести інтеграції мають різні цілі. Назви цих тестів не просто декоративні; вони також є описовими.
Роберт Харві

9
  1. Не перевіряйте банальні чи явні методи сховища.

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

    Це той самий принцип, що застосовується до тривіальних властивостей, як цей:

    public property SomeProperty
    {
        get { return _someProperty; }
        set { _someProperty = value; }
    }
    

    Ви не тестуєте це, тому що немає чого тестувати. У властивості немає перевірки чи іншої логіки, яку потрібно перевірити.

  2. Якщо ви все ще хочете перевірити ці методи ...

    Знущання - це спосіб це зробити. Пам'ятайте, це тестові одиниці. Ви не перевіряєте базу даних за допомогою одиничних тестів; ось для чого призначені інтеграційні тести.

Додаткова інформація
Повний стек, частина 3: Створення сховища за допомогою TDD (почніть перегляд приблизно через 16 хвилин).


3
Звичайно, я це розумію. І все-таки, якщо це TDD-підхід, я не повинен писати жодного коду, якщо спочатку у мене немає тестів на цей код, правда?
Тавен

1
@Thaven - на youtube є серія відео з назвою "tdd dead?". Спостерігайте за ними. Вони стосуються багатьох цікавих моментів, один з яких - це те, що застосування TDD на кожному рівні вашої програми не обов'язково є найкращою ідеєю. "жоден код без провального тесту" - це занадто екстремальна позиція, є одним із висновків.
Жуль

2
@Jules: Що таке tl; dw?
Роберт Харві

1
@RobertHarvey Важко підсумувати, але найважливішим моментом було те, що трактувати TDD як релігію, яку завжди слід дотримуватися, - це помилка. Вибір використовувати його є частиною компромісу, і вам потрібно врахувати, що (1) ви можете працювати швидше без цього над деякими проблемами, і (2) це може підштовхнути вас до більш складного рішення, ніж вам потрібно, особливо, якщо ви опинитесь, що ви використовуєте безліч глузувань.
Жуль

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