Когда вы пишете «настоящий» код в TDD?

147

Все примеры, которые я читал и видел на обучающих видео, имеют упрощенные примеры. Но что я не вижу, как я делаю «настоящий» код после того, как я становлюсь зеленым. Это часть "Refactor"?

Если у меня есть довольно сложный объект со сложным методом, и я пишу свой тест и минимальный минимум, чтобы он прошел (после первого сбоя, красный). Когда я вернусь и напишу настоящий код? И сколько реального кода я пишу перед повторным тестированием? Я предполагаю, что последний - больше интуиции.

Изменить: Спасибо всем, кто ответил. Все ваши ответы очень помогли мне. Кажется, есть разные идеи о том, что я спрашивал или смущал, и, может быть, есть, но я спрашивал, скажем, у меня есть заявление на строительство школы.

В моем дизайне у меня есть архитектура, с которой я хочу начать, пользовательские истории и так далее. Отсюда я беру эти пользовательские истории и создаю тест для проверки пользовательской истории. Пользователь говорит: у нас есть люди, которые записываются в школу и платят за регистрацию. Итак, я думаю о том, как это сделать. При этом я создаю тестовый класс для класса X (возможно, ученик), который не пройдёт. Я тогда создаю класс "Студент". Может быть, "Школа" я не знаю.

Но, в любом случае, TD Design заставляет меня задуматься над историей. Если я могу сделать тест неудачным, я знаю, почему он не проходит, но это предполагает, что я могу его пройти. Речь идет о разработке.

Я сравниваю это с мыслью о рекурсии. Рекурсия не сложная концепция. Может быть, на самом деле сложнее отслеживать это в своей голове, но на самом деле самое сложное - это знать, когда рекурсия «ломается», когда останавливаться (мое мнение, конечно.) Так что я должен думать о том, что останавливает Рекурсия первая. Это только несовершенная аналогия, и она предполагает, что каждая рекурсивная итерация является «проходом». Опять просто мнение.

В реализации, школу труднее увидеть. Цифровые и банковские регистры являются «простыми» в том смысле, что вы можете использовать простую арифметику. Я могу видеть a + b и возвращать 0 и т. Д. В случае системы людей, я должен подумать над тем, как это реализовать . У меня есть понятие провал, пасс, рефакторинг (в основном из-за изучения и этого вопроса.)

То, что я не знаю, основано на отсутствии опыта, по моему мнению. Я не знаю, как не подписать нового студента. Я не знаю, как ошибиться, если кто-то введет фамилию и она будет сохранена в базе данных. Я знаю, как сделать +1 для простой математики, но с такими объектами, как человек, я не знаю, проверяю ли я только, получаю ли я уникальный идентификатор базы данных или что-то еще, когда кто-то вводит имя в база данных или оба или нет.

Или, может быть, это показывает, что я все еще в замешательстве.

Джонни
источник
193
После TDD люди уходят домой на ночь.
Хоббс
14
Почему вы думаете, что написанный вами код не настоящий?
Гойо
2
@RubberDuck Больше, чем другие ответы. Я уверен, что я буду ссылаться на это в ближайшее время. Это все еще иностранное, но я не собираюсь отказываться от этого. То, что вы сказали, имело смысл. Я просто пытаюсь сделать так, чтобы это имело смысл в моем контексте или в обычном бизнес-приложении. Может быть, система инвентаризации или тому подобное. Я должен рассмотреть это. Я благодарен за ваше время, хотя. Благодарю.
джонни
1
Ответы уже бьют по голове, но пока все ваши тесты проходят успешно, и вам не нужны никакие новые тесты / функциональные возможности, можно предположить, что код, который вы получили, закончен, штриховая пометка.
ESR
3
Есть вопрос в вопросе, который может быть проблематичным в «У меня довольно сложный объект со сложным методом». В TDD вы сначала пишете свои тесты, поэтому начинаете с довольно простого кода. Это заставит вас кодировать удобную для тестирования структуру, которая должна быть модульной. Так сложное поведение будет создано путем объединения более простых объектов. Если вы заканчиваете с довольно сложным объектом или методом, тогда вам нужно
выполнить

Ответы:

242

Если у меня есть довольно сложный объект со сложным методом, и я пишу свой тест и минимальный минимум, чтобы он прошел (после первого сбоя, красный). Когда я вернусь и напишу настоящий код? И сколько реального кода я пишу перед повторным тестированием? Я предполагаю, что последний - больше интуиции.

Вы не «возвращаетесь» и не пишете «реальный код». Это все настоящий код. Что вы делаете, это возвращаетесь и добавляете еще один тест, который заставляет вас изменить свой код, чтобы пройти новый тест.

Что касается того, сколько кода вы пишете перед повторным тестированием? Никто. Вы пишете нулевой код без неудачного теста, который заставляет вас писать больше кода.

Обратите внимание на шаблон?

Давайте рассмотрим (другой) простой пример в надежде, что это поможет.

Assert.Equal("1", FizzBuzz(1));

Легко peazy.

public String FizzBuzz(int n) {
    return 1.ToString();
}

Не то, что вы бы назвали реальным кодом, верно? Давайте добавим тест, который вызывает изменения.

Assert.Equal("2", FizzBuzz(2));

Мы могли бы сделать что-то глупое if n == 1, но мы перейдем к правильному решению.

public String FizzBuzz(int n) {
    return n.ToString();
}

Здорово. Это будет работать для всех номеров, не относящихся к FizzBuzz. Какой следующий ввод заставит изменить производственный код?

Assert.Equal("Fizz", FizzBuzz(3));

public String FizzBuzz(int n) {
    if (n == 3)
        return "Fizz";
    return n.ToString();
}

И снова. Напишите тест, который еще не прошел.

Assert.Equal("Fizz", FizzBuzz(6));

public String FizzBuzz(int n) {
    if (n % 3 == 0)
        return "Fizz";
    return n.ToString();
}

И теперь мы покрыли все кратные три (которые также не кратны пяти, мы отметим это и вернемся).

Мы еще не написали тест для "Buzz", поэтому давайте напишем это.

Assert.Equal("Buzz", FizzBuzz(5));

public String FizzBuzz(int n) {
    if (n % 3 == 0)
        return "Fizz";
    if (n == 5)
        return "Buzz"
    return n.ToString();
}

И снова, мы знаем, что есть еще один случай, который нам нужно рассмотреть.

Assert.Equal("Buzz", FizzBuzz(10));

public String FizzBuzz(int n) {
    if (n % 3 == 0)
        return "Fizz";
    if (n % 5 == 0)
        return "Buzz"
    return n.ToString();
}

И теперь мы можем обрабатывать все кратные 5, которые также не кратны 3.

До этого момента мы игнорировали этап рефакторинга, но я вижу некоторое дублирование. Давайте очистим это сейчас.

private bool isDivisibleBy(int divisor, int input) {
    return (input % divisor == 0);
}

public String FizzBuzz(int n) {
    if (isDivisibleBy(3, n))
        return "Fizz";
    if (isDivisibleBy(5, n))
        return "Buzz"
    return n.ToString();
}

Здорово. Теперь мы удалили дублирование и создали хорошо названную функцию. Какой следующий тест, который мы можем написать, заставит нас изменить код? Что ж, мы избежали случая, когда число делится на 3 и 5. Давайте напишем это сейчас.

Assert.Equal("FizzBuzz", FizzBuzz(15));

public String FizzBuzz(int n) {
    if (isDivisibleBy(3, n) && isDivisibleBy(5, n))
        return "FizzBuzz";
    if (isDivisibleBy(3, n))
        return "Fizz";
    if (isDivisibleBy(5, n))
        return "Buzz"
    return n.ToString();
}

Тесты пройдены, но у нас больше дублирования. У нас есть варианты, но я собираюсь применить «Извлечь локальную переменную» несколько раз, чтобы мы вместо рефакторинга провели рефакторинг.

public String FizzBuzz(int n) {

    var isDivisibleBy3 = isDivisibleBy(3, n);
    var isDivisibleBy5 = isDivisibleBy(5, n);

    if ( isDivisibleBy3 && isDivisibleBy5 )
        return "FizzBuzz";
    if ( isDivisibleBy3 )
        return "Fizz";
    if ( isDivisibleBy5 )
        return "Buzz"
    return n.ToString();
}

И мы рассмотрели каждый разумный вклад, но как насчет необоснованного ввода? Что произойдет, если мы передадим 0 или отрицательный результат? Напишите эти тесты.

public String FizzBuzz(int n) {

    if (n < 1)
        throw new InvalidArgException("n must be >= 1);

    var isDivisibleBy3 = isDivisibleBy(3, n);
    var isDivisibleBy5 = isDivisibleBy(5, n);

    if ( isDivisibleBy3 && isDivisibleBy5 )
        return "FizzBuzz";
    if ( isDivisibleBy3 )
        return "Fizz";
    if ( isDivisibleBy5 )
        return "Buzz"
    return n.ToString();
}

Это уже начинает выглядеть как «реальный код»? Что еще более важно, в какой момент он перестал быть «нереальным кодом» и перешел в «реальный»? Об этом стоит подумать ...

Итак, я смог сделать это, просто посмотрев тест, который, как я знал, не пройдёт на каждом этапе, но у меня было много практики. Когда я на работе, все не так просто, и я не всегда знаю, какой тест приведет к изменениям. Иногда я пишу тест и удивляюсь, когда он уже пройден! Я настоятельно рекомендую вам привыкнуть создавать «Тестовый список» перед началом работы. Этот список тестов должен содержать все «интересные» входные данные, которые вы можете придумать. Вы можете не использовать их все, и вы, скорее всего, будете добавлять дела, но этот список служит дорожной картой. Мой список тестов для FizzBuzz будет выглядеть примерно так.

  • отрицательный
  • Нуль
  • Один
  • Два
  • Три
  • четыре
  • 5
  • Шесть (нетривиальное кратное 3)
  • Девять (3 в квадрате)
  • Десять (нетривиальное кратное 5)
  • 15 (кратно 3 и 5)
  • 30 (нетривиальное кратное 3 и 5)
Резиновая утка
источник
3
Комментарии не для расширенного обсуждения; этот разговор был перенесен в чат .
maple_shaft
47
Если я не совсем неверно понимаю этот ответ: «Мы могли бы сделать что-то глупое, как если бы n == 1, но мы перейдем к разумному решению». - все это было глупо. Если вы заранее знаете, что вам нужна функция, которая выполняет <spec>, напишите тесты для <spec> и пропустите часть, в которой вы пишете версии, которые явно не работают <spec>. Если вы обнаружите ошибку в <spec>, то обязательно: сначала напишите тест, чтобы убедиться, что вы можете выполнить его до исправления, и наблюдать за проходами теста после исправления. Но нет необходимости подделывать все эти промежуточные шаги.
GManNickG
16
Комментарии, которые указывают на основные недостатки в этом ответе и TDD в целом, были перенесены в чат. Если вы планируете использовать TDD, пожалуйста, прочитайте «чат». К сожалению, «качественные» комментарии теперь скрыты среди чата для чтения будущими студентами.
user3791372
2
@GManNickG Я считаю, что дело в том, чтобы получить правильное количество тестов. Предварительное написание тестов позволяет легко пропустить, какие особые случаи следует тестировать, что приводит либо к ситуациям, которые не освещаются должным образом в тестах, либо к по существу той же самой ситуации, бессмысленно охватывающей множество раз в тестах. Если вы можете сделать это без этих промежуточных шагов, здорово! Не все могут сделать это, хотя, это то, что требует практики.
17
1
А вот цитата из Кент Бека о рефакторинге: «Теперь, когда тест запускается, мы можем реализовать (как в« сделать реальностью ») реализацию summary ()». Затем он переходит к изменению константы на переменную. Я чувствовал, что эта цитата вполне соответствовала вопросу.
Крис Волерт
46

«Настоящий» код - это код, который вы пишете для прохождения теста. Действительно . Это так просто.

Когда люди говорят о написании минимума, чтобы сделать тест зеленым, это просто означает, что ваш реальный код должен следовать принципу YAGNI .

Идея этапа рефакторинга состоит в том, чтобы просто очистить то, что вы написали, когда вы будете удовлетворены требованиями.

Пока тесты, которые вы пишете, действительно соответствуют вашим требованиям к продукту, когда они пройдут, код будет завершен. Подумайте об этом, если у всех ваших бизнес-требований есть тест, и все эти тесты зеленого цвета, что еще можно написать? (Хорошо, в реальной жизни у нас нет склонности к полному тестовому освещению, но теория обоснована.)

GenericJon
источник
45
Модульные тесты не могут фактически охватить ваши требования к продукту даже для относительно тривиальных требований. В лучшем случае они пробуют пространство ввода-вывода, и идея заключается в том, что вы (правильно) обобщаете до полного пространства ввода-вывода. Конечно, ваш код может быть просто большим switchс кейсом для каждого модульного теста, который прошел бы все тесты и потерпел неудачу для любых других входных данных.
Дерек Элкинс,
8
@DerekElkins TDD обязывает проваливать тесты. Не сбои юнит-тестов.
Темыр
6
@DerekElkins - вот почему вы не просто пишете модульные тесты, а также почему существует общее предположение, что вы пытаетесь сделать что-то, а не просто подделать это!
Джоншарп
36
@jonrsharpe По этой логике я бы никогда не писал тривиальных реализаций. Например, в примере FizzBuzz в ответе RubberDuck (который использует только модульные тесты) первая реализация явно «просто подделывает». Мое понимание вопроса заключается именно в этой дихотомии между написанием кода, который, как вы знаете, является неполным, и кодом, который, как вы искренне полагаете, будет реализовывать требование, «настоящий код». Мой «большой switch» был задуман как логическая крайность «написания минимума, чтобы сделать тесты зелеными». Я рассматриваю вопрос ОП как: где в TDD принцип, который избегает этого большого switch?
Дерек Элкинс
2
@ GenericJon Это слишком оптимистично в моем опыте :) Во-первых, есть люди, которым нравится бездумная повторяющаяся работа. Они будут счастливее с гигантским заявлением о переключении, чем с «сложным принятием решений». И чтобы потерять работу, им либо понадобится кто-то, кто вызовет их на эту технику (и им лучше иметь веские доказательства того, что на самом деле они теряют возможности / деньги компании), либо делать это исключительно плохо. После того, как я взял на себя обслуживание многих таких проектов, я могу сказать, что очень наивный код легко может длиться десятилетиями, пока он делает клиента счастливым (и платящим).
Луаан
14

Краткий ответ: «реальный код» - это код, который проходит тест. Если вы можете пройти тест с помощью чего-то другого, кроме реального кода, добавьте больше тестов!

Я согласен, что многие учебники о TDD являются упрощенными. Это работает против них. Слишком простой тест для метода, который, скажем, вычисляет 3 + 8, действительно не имеет другого выбора, кроме как также вычислить 3 + 8 и сравнить результат. Это создает впечатление, что вы просто дублируете код повсюду, и это тестирование является бессмысленной, подверженной ошибкам дополнительной работой.

Когда вы хорошо разберетесь в тестировании, вы узнаете, как вы структурируете свое приложение и как вы пишете свой код. Если у вас возникли проблемы с продуманными и полезными тестами, вам, вероятно, следует немного переосмыслить свой дизайн. Хорошо спроектированная система легко тестируется - это означает, что разумные тесты легко продумать и реализовать.

Когда вы сначала пишете свои тесты, наблюдаете, как они проваливаются, а затем пишете код, который делает их успешными, это дисциплина, гарантирующая, что весь ваш код имеет соответствующие тесты. Я не рабски следую этому правилу, когда пишу код; часто пишу тесты по факту. Но выполнение тестов в первую очередь помогает вам быть честным. Имея некоторый опыт, вы начнете замечать, когда закодируете себя в угол, даже если вы сначала не пишете тесты.

Карл Рэймонд
источник
6
Лично я бы написал тест assertEqual(plus(3,8), 11), а не assertEqual(plus(3,8), my_test_implementation_of_addition(3,8)). В более сложных случаях вы всегда ищете способ доказать правильный результат, кроме динамического вычисления правильного результата в тесте и проверки равенства.
Стив Джессоп
Так что для действительно глупого способа сделать это для этого примера вы можете доказать, что plus(3,8)вернул правильный результат, вычтя из него 3, вычтя из этого 8 и сравнив результат с 0. Это так очевидно эквивалентно тому, assertEqual(plus(3,8), 3+8)чтобы быть немного абсурдно, но если тестируемый код строит нечто более сложное, чем просто целое число, то взятие результата и проверка каждой части на правильность часто является правильным подходом. В качестве альтернативы, что-то вродеfor (i=0, j=10; i < 10; ++i, ++j) assertEqual(plus(i, 10), j)
Стив Джессоп
... поскольку это позволяет избежать большого страха, заключающегося в том, что при написании теста мы допустим ту же ошибку по вопросу «как добавить 10», которую мы сделали в живом коде. Поэтому тест тщательно избегает написания любого кода, который добавляет 10 ко всему, в тесте, который plus()может добавить 10 к вещам. Конечно, мы все еще полагаемся на проверенные программистом значения начальных циклов.
Стив Джессоп
4
Просто хочу отметить, что даже если вы пишете тесты после факта, все равно будет хорошей идеей наблюдать, как они проваливаются; найдите некоторую часть кода, которая кажется критически важной для всего, над чем вы работаете, слегка подправьте его (например, замените + на - или что-то еще), запустите тесты и посмотрите, как они проваливаются, отмените изменение и проследите, как оно прошло. Много раз я делал это, тест на самом деле не терпит неудачу, делая его хуже, чем бесполезным: он не только ничего не тестирует, но и дает мне ложную уверенность в том, что что-то тестируется!
Варбо
6

Иногда некоторые примеры о TDD могут вводить в заблуждение. Как уже отмечали другие люди, код, который вы пишете для прохождения тестов, является реальным кодом.

Но не думайте, что настоящий код выглядит как волшебство - это неправильно. Вам нужно лучше понять, чего вы хотите достичь, а затем вам нужно выбрать тест соответственно, начиная с самых простых случаев и угловых случаев.

Например, если вам нужно написать лексер, вы начинаете с пустой строки, затем с группы пробелов, затем числа, затем с числом, окруженным пробелами, затем неправильным числом и т. Д. Эти небольшие преобразования приведут вас к правильный алгоритм, но вы не перепрыгнете с самого простого случая на очень сложный случай, выбранный тупо, чтобы получить реальный код.

Боб Мартин прекрасно объясняет это здесь .

Виктор Сеюдо
источник
5

Часть рефактора очищается, когда вы устали и хотите пойти домой.

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

Это может быть столь же просто , как переименование , GreetImplчтобы GreetWorldперед тем, как создать GreetMomкласс (после добавления теста) , чтобы добавить функцию , которая будет печатать «Привет мама».

candied_orange
источник
1

Но реальный код появится на стадии рефакторинга фазы TDD. Т.е. код, который должен быть частью финальной версии.

Тесты должны выполняться каждый раз, когда вы вносите изменения.

Девиз жизненного цикла TDD будет следующим: RED GREEN REFACTOR

КРАСНЫЙ : написать тесты

ЗЕЛЕНЫЙ : Сделайте честную попытку получить функциональный код, который проходит тесты как можно быстрее: дублирующий код, неизвестные переменные, хаки высшего порядка и т. Д.

РЕФАКТОР : Очистите код, правильно назовите переменные. СУШИТЕ код.

Graeme
источник
6
Я знаю, что вы говорите о «зеленой» фазе, но это подразумевает, что жесткие возвращаемые значения для прохождения тестов могут быть уместными. По моему опыту, «зеленый» должен быть честной попыткой сделать рабочий код для удовлетворения требований, он может быть не идеальным, но он должен быть настолько полным и «доставляемым», насколько разработчик может управлять за первый проход. Рефакторинг, вероятно, лучше всего выполнить через некоторое время после того, как вы проделали большую разработку, и проблемы с первым проходом станут более очевидными и появятся возможности для СУХОГО.
Маккотл
2
@mcottle: вы можете быть удивлены тем, сколько реализаций репозитория только для получения может быть жестко закодированными значениями в кодовой базе. :)
Брайан
6
Зачем мне когда-либо писать дерьмовый код и очищать его, когда я могу получить хороший, качественный производственный код почти так же быстро, как я могу печатать? :)
Kaz
1
@Kaz Потому что таким образом вы рискуете добавить непроверенное поведение . Единственный способ обеспечить тестирование для каждого желаемого поведения - это сделать простейшее возможное изменение независимо от того, насколько оно дрянное. Иногда следующий рефакторинг поднимает новый подход, о котором вы заранее не задумывались ...
Тимоти Траклле
1
@TimothyTruckle Что, если для поиска простейшего изменения требуется 50 минут, а для поиска второго простейшего изменения - всего 5 минут? Мы идем со вторым самым простым или продолжаем искать самое простое?
Каз
1

Когда вы пишете «настоящий» код в TDD?

Красная фаза , где писать код.

На этапе рефакторинга основной целью является удаление кода.

В красной фазе вы делаете все, чтобы пройти тест максимально быстро и любой ценой . Вы полностью игнорируете то, что когда-либо слышали о хороших методах кодирования или шаблонах проектирования. Сделать тест зеленым - это все, что имеет значение.

На этапе рефакторинга вы убираете только что созданный беспорядок. Теперь вы сначала посмотрите, является ли изменение, которое вы только что внесли, самым верхним в списке Приоритет преобразования, и если есть какое-либо дублирование кода, вы, скорее всего, можете удалить его, применив шаблон проектирования.

Наконец, вы улучшаете читабельность, переименовывая идентификаторы и извлекая магические числа и / или буквенные строки в константы.


Это не красный рефактор, это красный, зеленый рефактор. - Роб Киньон

Спасибо за указание на это.

Так что это зеленая фаза, где вы пишете реальный код

В красной фазе вы пишете исполняемую спецификацию ...

Тимоти Тракл
источник
Это не красный рефактор, это красный, зеленый рефактор. «Красный» означает, что вы выбираете набор тестов с зеленого (все тесты пройдены) на красный (один тест не пройден). «Зеленый» - это то, где вы небрежно переводите свой набор тестов с красного (один тест не пройден) на зеленый (все тесты пройдены). «Рефакторинг» - это то, где вы берете свой код и делаете его красивым, сохраняя при этом все тесты пройденными.
Роб Киньон
1

Вы пишете настоящий код все время.

На каждом этапе Вы пишете код, удовлетворяющий условиям, которые будет выполнять Ваш код для будущих абонентов Вашего кода (которые могут быть Вами или нет ...).

Вы думаете, что не пишете полезный ( настоящий ) код, потому что через мгновение вы можете его реорганизовать.

Рефакторинг кода - это процесс реструктуризации существующего компьютерного кода - изменение факторинга - без изменения его внешнего поведения.

Это означает, что, даже если Вы меняете код, условия, которые он выполнял, остаются без изменений. И проверки ( тесты ), которые Вы реализовали для проверки Вашего кода, уже существуют, чтобы проверить, изменились ли Ваши изменения. Таким образом, код, который Вы написали все время, там, просто по-другому.

Другая причина, по которой вы можете подумать, что это не настоящий код, заключается в том, что вы делаете примеры, когда конечная программа уже может быть предвидена вами. Это очень хорошо, так как он показывает вас есть знания о домене Вы программируете в.
Но много раз программистов в области , которая является новой , неизвестной им. Они не знают, каким будет конечный результат, и TDD - это метод написания программ шаг за шагом, документирующий наши знания о том, как должна работать эта система, и проверка того, что наш код работает таким образом.

Когда я читал «Книгу» (*) на TDD, для меня наиболее важной особенностью был список TODO. Это показало мне, что TDD также является техникой, помогающей разработчикам сосредоточиться на одной вещи за раз. Так что это также ответ на Ваш вопрос о том, сколько Реального кода написать ? Я бы сказал, достаточно кода, чтобы сосредоточиться на одной вещи за раз.

(*) «Разработка через тестирование: на примере» Кента Бека

Роберт Анджейюк
источник
2
«Разработка через тестирование: на примере» Кента Бека
Роберт
1

Вы не пишете код, чтобы сделать ваши тесты неудачными.

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

Весь смысл написания изначально неудачных тестов состоит в том, чтобы сделать две вещи:

  1. Покройте все случаи - все номинальные случаи, все крайние случаи и т. Д.
  2. Подтвердите свои тесты. Если вы только когда-либо видели, как они проходят, как вы можете быть уверены, что они надежно сообщат о сбое, когда оно произойдет?

Смысл красно-зеленого-рефактора в том, что написание правильных тестов сначала дает вам уверенность в том, что код, который вы написали для прохождения тестов, является правильным, и позволяет вам проводить рефакторинг с уверенностью, что ваши тесты сообщат вам, как только что-то ломается, поэтому вы можете сразу же вернуться и починить это.

По моему собственному опыту (C # /. NET), чистый первый тест - это недостижимый идеал, потому что вы не можете скомпилировать вызов метода, который еще не существует. Таким образом, «сначала проверка» на самом деле касается кодирования интерфейсов и реализации заглушек, а затем написания тестов для заглушек (которые первоначально не пройдут) до тех пор, пока заглушки не будут правильно выделены. Я никогда не пишу «провальный код», просто строю из заглушек.

Zenilogix
источник
0

Я думаю, вы можете запутаться между юнит-тестами и интеграционными тестами. Я считаю, что также могут быть приемочные испытания, но это зависит от вашего процесса.

После того, как вы проверили все маленькие «блоки», вы тестируете их в собранном виде или «интегрированы». Обычно это целая программа или библиотека.

В написанном мной коде интеграция тестирует библиотеку с различными тестовыми программами, которые считывают данные и передают их в библиотеку, а затем проверяют результаты. Тогда я делаю это с потоками. Затем я делаю это с потоками и fork () посередине. Затем я запускаю его и через 2 секунды убиваю -9, затем запускаю и проверяю его режим восстановления. Я размышляю над этим. Я мучаю это всеми способами.

Все это ТАКЖЕ тестирование, но у меня нет довольно красного / зеленого дисплея для результатов. Это либо успешно, либо я копаю несколько тысяч строк кода ошибки, чтобы выяснить, почему.

Вот где вы тестируете «реальный код».

И я только что подумал об этом, но, возможно, вы не знаете, когда вам следует писать модульные тесты. Вы закончили написание модульных тестов, когда ваши тесты выполняют все, что вы должны сделать. Иногда вы можете потерять отслеживание этого среди всех случаев обработки ошибок и крайних случаев, поэтому вы можете захотеть создать хорошую группу тестов счастливого пути, которые просто идут по спецификациям.

Зан Рысь
источник
(его = притяжательное, это = "оно есть" или "оно имеет". См., например, как использовать его и оно есть .)
Питер Мортенсен
-6

В ответ на заголовок вопроса: «Когда вы пишете« реальный »код в TDD?», Ответ: «почти никогда» или «очень медленно».

Вы говорите как студент, поэтому я отвечу так, как будто советую студенту.

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

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

Но вам нужно знать, как разбить ваше приложение, чтобы иметь возможность разрабатывать достойный код. Например, если вы не знали о Little Bobby Table (xkcd 327), то, вероятно, вы не очистите свои входные данные перед работой с базой данных, поэтому вы не сможете защитить свои данные с помощью этой концепции.

TDD - это просто рабочий процесс, предназначенный для минимизации ошибок в вашем коде путем создания тестов того, что может пойти не так, прежде чем кодировать ваше приложение, потому что кодирование может стать экспоненциально сложным, чем больше кода вы вводите, и вы забываете ошибки, о которых когда-то думали. Когда вы думаете, что завершили свое приложение, вы запускаете тесты и бум, надеюсь, ошибки будут обнаружены в ваших тестах.

TDD - это, как полагают некоторые, не написать тест, выполнить его с минимальным кодом, написать другой тест, получить его с минимальным кодом и т. Д. Вместо этого, это способ помочь вам уверенно писать код. Этот идеал непрерывного рефакторинга кода, чтобы заставить его работать с тестами, является идиотским, но это хорошая идея среди студентов, потому что это заставляет их чувствовать себя прекрасно, когда они добавляют новую функцию, и они все еще учатся кодировать ...

Пожалуйста, не бросайте эту ловушку и посмотрите, какова ваша роль кодирования - работа кодера заключается исключительно в создании кода. Код, который работает действительно хорошо. Теперь помните, что вы будете профессиональным программистом, и вашему клиенту будет все равно, если вы напишите 100 000 утверждений или 0. Они просто хотят, чтобы код работал. Действительно хорошо, на самом деле.

user3791372
источник
3
Я даже не близко к студенту, но я читаю и пытаюсь применять хорошие методы и быть профессиональным. Так что в этом смысле я «студент». Я просто задаю очень простые вопросы, потому что я такой. Мне нравится точно знать, почему я делаю то, что делаю. Суть дела. Если я этого не понимаю, мне это не нравится, и я начинаю задавать вопросы. Мне нужно знать почему, если я собираюсь использовать это. TDD кажется интуитивно хорошим в некотором смысле, например, зная, что нужно для создания и продумывая вещи, но реализацию было трудно понять. Я думаю, что теперь я лучше понимаю.
джонни
4
Это правила TDD. Вы можете писать код так, как хотите, но если вы не следуете этим трем правилам, вы не выполняете TDD.
Шон Бертон,
2
«Правила» одного человека? TDD - это предложение помочь вам кодировать, а не религия. Грустно видеть, что так много людей придерживаются идеи так анально. Даже происхождение TDD является спорным.
user3791372
2
@ user3791372 TDD - очень строгий и четко определенный процесс. Даже если многие думают, что это просто означает «Проведите некоторое тестирование во время программирования», это не так. Попробуем не путать здесь термины, этот вопрос касается процесса TDD, а не общего тестирования.
Алекс