У TDD мені слід спочатку написати тест або інтерфейс?


23

Я вивчаю TDD за допомогою c #, наскільки я знаю, тест повинен керувати розвитком , тобто спочатку написати провальний тест після написання голого мінімального коду, щоб пройти тест, потім зробити рефакторинг.

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

  1. Код, написаний для інтерфейсу, не керується тестом .

  2. Очевидно, що це не мінімальний мінімум, я можу написати це простим класом.

Чи варто починати також із написання тестів для інтерфейсу? без будь-якої реалізації, що я буду тестувати?

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


8
"Програма на інтерфейс" означає відділення того, що вам потрібно від фрагмента коду, від того, як це робиться. Це не означає буквально використовувати interfaceдля всього. А classтакож надає інтерфейс, оскільки ви можете приховати деталі реалізації у privateзмінних.
Doval

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

2
TDD каже: "написати тест, який не вдається". Деякі суворі TDDers кажуть, що він вважається "провалом", якщо ви не можете скласти тест, оскільки тип даних, для якого він працює, ще не був оголошений.
Соломон повільно

Відповіді:


29

Ваше перше порушення ("Код, написаний для інтерфейсу, не керується тестом.") Недійсний. Давайте скористаємось тривіальним прикладом. Припустимо, ви пишете клас калькулятора і ви пишете операцію додавання. Який тест ви можете написати?

public class CalculatorTest {
    @Test
    public void testAddTwoIntegers() {
        Calculator calc = new Calculator();
        int result = calc.add(2, 2)
        Assert.assertEquals(4, result);
    }
}

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

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

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


2
+1 " Я не думаю, що ви можете відокремити дизайн інтерфейсу від тестового дизайну ", слід виділити жирним шрифтом, ІМХО :)
Бінарний поварот

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

Ви кажете, що тест не потрібно змінювати, але new Calculator()чи правильно це реалізація? Якщо вам потрібна нова реалізація, можливо, ви б тоді зробили MultiplicationCalculator, і вам потрібно буде змінити тест, щоб використовувати new AdditionCalculator()його, щоб він все-таки пройшов? Або я щось пропускаю?
Стів Чамайлард

3
@SteveChamaillard Звичайно, якщо у вашому дизайні ви змінили назву класу з Калькулятора на AdditionCalculator, тест повинен був би змінити, щоб він відповідав. Звичайно, зробивши TDD, що насправді трапиться, ви б спершу змінили тест, а зміна класу настала б для того, щоб тест пройшов.
Ерік Кінг

5

Що ми робимо, коли пишемо interface? Ми пишемо код чи проектуємо?

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

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


4

У TDD мені слід спочатку написати тест або інтерфейс?

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

Я вивчаю TDD

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

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

  2. Окрім TDD чи ні: Питання, використовувати інтерфейс чи ні, в першу чергу не цікавий. Звичайно, якщо ви впевнені, у вас є інша поведінка, яку ви хочете поширити на кілька об'єктів, є сенс подумати про використання інтерфейсу: Наприклад, якщо у вас є якийсь вихід на різні напрямки, є сенс реалізувати це через інтерфейс Writer і мають різні класи для виводу ( FileWriter , принтер тощо). Хоча звичайна приказка писати в інтерфейс , але це не означає: використовувати інтерфейс для всього . Іноді це один рівень опосередкованості на багато. Btw. те саме стосується послуг. Але це вже інша тема.

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


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

4
Як я вже сказав ... Це залежить від того, наскільки ти православний ...
Томас Джунк

2

TDD або BDD означало б спочатку зробити свій доменний інтерфейс, а потім написати тести проти них за моєю інтерпретацією. реалізація інтерфейсу має очікувану поведінку.

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

Я зробив би це так

  1. Напишіть напівформальну поведінку (Дано: Коли: Тоді :)

  2. Написати інтерфейс (для методу інкапсуляції поведінки хоста)

  3. Напишіть тест ідентифікує (введіть задане, зателефонуйте коли, протестуйте потім)

  4. Написати / змінити бетон (Клас, який реалізує інтерфейс) для проходження тесту


0

Ніколи не пишіть тести, перш ніж ви спроектували інтерфейси. Коли ви думаєте про те, які типи тестів написати (тестовий дизайн), ви також не повинні одночасно проектувати (архітектуру) вашої програми. Не думайте про дві речі одночасно. Ви чули про роз'єднання проблем? Це стосується не лише фізичної структури вашого коду, але і вашого мислення.

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


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

@gnat Я вважаю, що Nissam тут має на увазі interfaceключове слово C # , а не загальний термін "інтерфейс".
RubberDuck

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

Досить справедливо @gnat, що не було зрозуміло з вашого коментаря. Особисто я згоден з Ніссамом тут. Я вважаю, що це заважає людям використовувати TDD як привід взагалі не створювати дизайн. YMMV.
RubberDuck

-2

Добре написати інтерфейс / код / ​​тест одночасно, якщо їх включення в проект є атомним.

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

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