Актуальность тестирования красного зеленого света - PullRequest
1 голос
/ 01 января 2009

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

Я чувствую, что не могу правильно написать провальный или проходящий тест без реализации кода, который я собираюсь протестировать. Например, если я напишу тест, чтобы показать, что мой DataProvider возвращает DataRow, мне нужно написать логический DAL для значимого сбоя, сбоя, превышающего NullException, или возврата Null из пустого метода, что-то, что кажется бессмысленно, так как я чувствую, что красный свет должен показать, что я могу создать неудавшийся тест из фактической логики, которую я тестирую.

Другими словами, если я просто возвращаю значение null или false, из функции, которую я тестирую, чтобы получить мой сбой, что на самом деле является значением красного света.

Однако, если я уже реализовал логическую (что в некотором смысле противоречит первой парадигме теста), я обнаружил, что просто тестирую взаимоисключающие концепции (IsTrue вместо IsFalse или IsNull вместо IsNotNull) только ради получить красный свет вместо зеленого, а затем переключить их на противоположный, чтобы получить пропуск.

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

EDIT

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

Ответы [ 5 ]

9 голосов
/ 01 января 2009

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

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

3 голосов
/ 01 января 2009

Думайте об этом как о спецификации. Вы начинаете , спрашивая себя: "Что должен делать код, который я в конечном итоге хочу?" Итак, скажем, вы хотите написать функцию, которая добавляет натуральные числа. Как бы вы узнали, сработало ли это? Ну, вы знаете, что 2 + 2 = 4, так что вы можете написать тест (это в основном python, но опущено много деталей, см. Документацию unittest module ):

def test2plus2(self):
    assertEquals(addNat(2,2), 4)

Итак, здесь вы определили спецификацию, которая гласит: «Для натуральных чисел a и b вычислите a + b». Теперь вы знаете, что нужно для написания функции :

def addNat(a,b):
    return a+b

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

def testUnnatural(self):
    failUnlessRaises(AssertionErrof, addNat(-1, 2))

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

def addNat(a,b):
    """Version two"""
    assert((a >= 0) and (b>=0))
    return a+b

Запустите это сейчас, и утверждение не сработает; снова успех.

Дело в том, что TDD - это способ определения очень четких подробных спецификаций. Для чего-то вроде «addNat» они не нужны, но в реальном коде, особенно в гибком мире, вы не знаете ответ интуитивно. TDD поможет вам разобраться в этом и найти реальные требования,

1 голос
/ 01 января 2009

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

После написания кода, генерирующего исключение, я приступаю к написанию первого теста для функции, над которой я работаю, и получаю первый красный свет (предположительно). Теперь я могу продолжить обычный ритм TDD - Red-Green-Refactor. Не забудьте этот последний шаг. Рефакторинг при прохождении тестов, а не при написании кода для исправления неудачного теста.

Этот подход требует дисциплины, а иногда кажется, что вы делаете глупости, поскольку обычно для прохождения первого теста проще всего вернуть некоторые жестко закодированные данные. Продолжайте, хотя; Эта фаза начальной загрузки является относительно короткой, и если вы не пропустите ее, вы можете обнаружить, что вы пишете более простой и более обслуживаемый код, чем в противном случае, если бы ваше решение (или, по крайней мере, скелет) волшебным образом превратилось в целое в первом тесте. Если вы не развиваетесь небольшими шагами, вы не делаете TDD.

Обязательный отказ от ответственности: не забывайте, что TDD о модульном тестировании. Существуют другие виды тестирования (интеграция, приемка, загрузка, ...), и необходимость в других типах тестирования не исчезает волшебным образом, когда вы начинаете выполнять TDD.

1 голос
/ 01 января 2009

Я не уверен, что понимаю вашу точку зрения, но вот как я вижу это.

Меньше думайте о том, что возвращает функция, и больше о том, что она делает, и что она считает истинной.

Если моя функция true / false является языковой версией следующей функции C:

bool isIntPrime( int testInt )

тогда вы хотите убедиться, что тест не пройден, если вы пройдете его дважды (вместо того, чтобы иметь место «полезное» неявное приведение, которое вы можете встретить на некоторых языках).

Если вы действительно не можете найти «красный свет», тогда ваш «зеленый свет» в значительной степени не имеет смысла. Если вы действительно сталкиваетесь с таким случаем, то тестирование, вероятно, не будет стоить многого, поэтому тестирование этой функции / функции является пустой тратой времени. Возможно, это так просто и надежно, что, по сути, не может потерпеть неудачу? Тогда написание множества тестов «зеленого света» - пустая трата времени.

Это похоже на мысленный эксперимент с белым кроликом. Если я утверждаю, что все кролики коричневые, то подсчет коричневых кроликов ничего не даст для установления правдивости моего заявления. Тем не менее, первый белый кролик, которого я вижу, доказывает, что мое утверждение неверно.

Этот тривиальный пример помогает вообще?

1 голос
/ 01 января 2009

Есть несколько мотивирующих примеров, которые я могу вспомнить, почему красный свет полезен и очень помог мне.

  1. Написание красного теста для здравомыслия. Я уверен, что тест работает, чтобы проверить некоторую функцию, о которой я знаю, не реализованную, но ДЕЙСТВИТЕЛЬНО ДЕЙСТВИТЕЛЬНО ДЕЙСТВИТЕЛЬНО не.

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

Вероятно, есть один пример, когда красный свет бесполезен, и когда вы пишете тесты для проверки работоспособности, они обычно зеленые с самого начала. Тем не менее, я бы предупредил вас о написании «зеленых» тестов. Может случиться так, что вам придется перепроектировать классы и т. Д. С финансовой точки зрения, что делает некоторые тесты устаревшими. Вся эта зеленая проверка написана даром!

...