Чому в модульному тестуванні я б створив сховище двічі?


10

Днями я читав трохи про Unit Testing і побачив кілька прикладів, коли люди створюють інтерфейс сховища (тобто IExampleRepository), а потім створюють реальне сховище ( public class ExampleRepository : IExampleRepository) і сховище, яке буде використовуватися для тестування одиниць ( FakeExampleRepository : IExampleRepository).

У IExampleRepositoryних вони реалізовували ті ж методи, що й у ExampleRepositoryзапитах, однак із різними запитами Linq.

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

Відповіді:


8

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

Це означає, що вам також потрібно протестувати з "реальним" сховищем *, але це зазвичай робиться в інтеграційному / системному тесті

* очевидно реально, як у репо, створеному для тестування, сподіваємось, наприклад, не виробничий БД.


Отже, в одиничному тестуванні я не буду тестувати сам метод, щоб переконатися, що він повертає правильні значення (засновані на підробленому / глубокому наборі даних)?
джао

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

1
Гаразд, тому якщо я правильно розумію, я повинен використовувати оригінальний сховище під час тестування одиниць сховищ. Мені не потрібно , щоб перевірити їх , коли я пишу тести для контролерів (в разі Asp.Net MVC)
Жао

4
@Theomax Залежить від контексту: якщо ви перевіряєте програмний компонент, який не є вашим ExampleRepository, то краще використовувати макет. Виправданням є те, що ви не тестуєте одиницю сховища, а щось інше.
Андрес Ф.

5
@Theomax Щоб розширити коментар AndresF.: Якщо ви перевіряєте одиницю ExampleRepository, використовуйте справжню річ. Якщо ви перевіряєте одиницю RepositoryController, тоді слід використовувати лише a, FakeExampleRepositoryяке повертає попередньо задані значення. Таким чином, якщо помилка підкрадеться до ExampleRepository, тільки тест одиничного тесту не вдасться - RepositoryControllerтести продовжуватимуться успішно, тож ви знаєте, що помилки там немає. Якби контролер використовував реальне сховище, вони б не працювали, і ви б не знали, чи не було у вас помилки або 2.
Ізката

5

Я згоден з двома відповідями jk. та Ян Худек - вони дають дійсно хорошу інформацію. Але я думав, що трохи додам.

Ваше перше запитання ("Яка саме тут мета?") Є важливою. У випадку, який ви описуєте, реальною метою є тестування класів, які використовують IExampleRepositoryінтерфейс, а не тестування реалізацій репозиторію. Створення FakeExampleRepositoryдозволяє тестувати ці клієнтські класи, не турбуючись про деталі реального класу репозиторію.

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

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


the real objective is to test the classes that are utilizing the IExampleRepository interfaceце не зовсім вірно. Мета - перевірити його незалежно від IExampleRepository. +1 за те, щоб рекомендувати хорошу ізоляційну рамку.
StuperUser

1
Я не погоджуюсь. Це не є незалежним, IExampleRepositoryоскільки тестований клас приєднаний до цього інтерфейсу. Але це не залежить від будь-яких реалізацій інтерфейсу. Я визнаю, що моє пояснення могло б використовувати трохи більше тонкощів. :)
Аллан

5

Яка саме тут мета?

Ізоляція.

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

Створюючи підроблені класи, єдиним виробничим кодом є тестований клас.

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

Погляньте на структури ізоляції (наприклад, Moq, як це запропонував @Allan), щоб мати змогу швидко генерувати ці підробки для встановлення тестових умов і використовувати їх для затвердження.


Більш докладної інформація про підробки, знущаються і корінці: stackoverflow.com/questions/346372 / ...
StuperUser

4

Є три причини, чому ви можете надати макетний екземпляр для тестування блоку:

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