Следует ли писать модульные тесты до написания кода?

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

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

Раньше я пытался писать свои модульные тесты, и это может быть полезно, но мне это не кажется естественным.

Пожалуйста, сделайте это сообщество вики, так как это больше, чем опрос, чем реальный вопрос.

Sunny Milenov 29.10.2008 17:51

Это должен быть настоящий вопрос, а не очередной опрос. Я бы предпочел, чтобы Омар немного изменил формулировку вопроса, чтобы сделать его правильным, а не вопросом типа опроса.

David Arno 29.10.2008 17:53

Я счастлив перефразировать, но не уверен, на что это переформулировать.

Omar Kooheji 29.10.2008 17:56

Как насчет чего-нибудь вроде «Когда лучше всего писать модульные тесты, до того, как вы начнете кодировать, или после того, как закончите?»

Elie 29.10.2008 17:57

Мне было бы интересно узнать методологию, которую все используют для написания своих модульных тестов. Пытаются ли они полностью разобраться в проблеме перед написанием тестов? Или они пишут тесты, основанные на текущем понимании, и изменяют эти тесты позже, если понимание изменится?

George Stocker 29.10.2008 17:57

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

David Arno 29.10.2008 17:59

Дэвид, мне это нравится.

Omar Kooheji 29.10.2008 18:27
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
24
7
7 544
20
Перейти к ответу Данный вопрос помечен как решенный

Ответы 20

Не всегда, но я считаю, что это действительно помогает, когда я это делаю.

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

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

Я не знаю, является ли это ошибкой в ​​моем мышлении или методе или просто в TIMTOWTDI.

TIMTOWTDI? что это вообще такое?

Omar Kooheji 29.10.2008 17:58

Есть несколько способов сделать это. Код + тесты примерно в то же время еще можно тестировать. Набросайте код, напишите хорошие тесты, доделайте код.

S.Lott 29.10.2008 18:18

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

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

Так что, если вы пишете тесты после того, как написали код, это хорошо для вас, я бы посоветовал вам придерживаться этого.

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

не могли бы вы дать ссылки на исследования? Спасибо

roundcrisis 29.10.2008 17:57

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

Scott Lawrence 29.10.2008 19:42

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

David Arno 29.10.2008 22:24

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

picker = Pick.new
item=picker.pick('a')
assert item

тогда я создаю

class Pick
 def pick(something)
 return nil
 end
end

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

Итак, короче. да. Соотношение, когда вы проходите тестирование раньше, намного выше, чем когда вы его не проводите.

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

Вы можете начать с "Историй", которые могут выглядеть примерно так:

«Пользователи могут получить список вопросов»

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

«Класс пользователя имеет имя DOB-адрес TelNo Locked Fields»

и т.п. Надеюсь, это поможет.

Лукавый

Да, если вы используете настоящие принципы TDD. В противном случае, пока вы пишете модульные тесты, у вас все получается лучше, чем у большинства.

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

Я пишу их одновременно. Я создаю скелетный код для нового класса и тестового класса, а затем пишу тест для некоторых функций (который затем помогает мне увидеть, как я хочу, чтобы новый объект вызывался), и реализую его в коде.

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

Ответ принят как подходящий

Здесь есть несколько хороших комментариев, но я думаю, что одна вещь игнорируется.

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

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

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

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

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

Pokus 30.10.2008 01:25

Пусть IDE сгенерирует заглушку метода. Сначала все тесты не пройдут.

flukus 30.10.2008 02:22

@Pokus - быстрый ответ ... Я выключаю автоматическое завершение операторов, чтобы intellisense не мешал мне. CTRL + пробел всегда будет вызывать его, если мне это нужно. Я очень рекомендую ReSharper (jetbrains.com/resharper). Это сильно помогает моему рабочему процессу TDD.

Ben Scheirman 30.10.2008 16:13

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

Omar Kooheji 30.10.2008 18:16

@Ben - вы можете очистить список символов, которые будут фиксироваться из списка автозаполнения; тогда это сделает только TAB. Лучшее обоих миров.

Jay Bazuzi 29.12.2008 20:01

правда ли, что TDD только для опытных людей? как новый программист могу я еще попробовать?

Kunal Balani 06.12.2013 00:03

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

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

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

Итак, мой голос: Сначала тест

PS: И нет, это не означает, что вам не нужно планировать свою архитектуру раньше, но что вы можете переосмыслить ее, если тесты скажут вам это сделать !!!!

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

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

Обычно сложнее всего понять требования, а за ними - удобство использования вашего класса, API, пакета ... Затем - фактическая реализация.

  1. Напишите свои интерфейсы (они будут меняться, но будут иметь большое значение, чтобы знать, что нужно выполнить КАКИЕ)
  2. Напишите простую программу для использования интерфейсов (тупой их основной). Это имеет большое значение для определения КАК, которое будет использоваться (возвращайтесь к 1 по мере необходимости)
  3. Напишите тесты в интерфейсе (бит, который я интегрировал из TDD, снова возвращайтесь к 1 так часто, как это необходимо)
  4. напишите фактический код за интерфейсами
  5. напишите тесты для классов и фактической реализации, используйте инструмент покрытия, чтобы убедиться, что вы не забыли пути выполнения weid

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

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

Это строго говоря TDD? Экстремальный? Гибкий...? что бы ни... ? Я не знаю, и, честно говоря, мне все равно. Работает для меня. Я корректирую его по мере необходимости и по мере развития моего понимания практики разработки программного обеспечения.

мои 2 цента

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

Разработка через тестирование (TDD) помогает нам ответить на вопрос «Что?» прежде чем мы ответим "Как?" и это имеет большое значение.

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

Лично я считаю, что модульные тесты сильно теряют свою эффективность, если их не провести до написания кода.

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

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

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

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

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

Часто, если нет тестовой среды, я просто пишу main () в каждом написанном мной классе. Это добавляет немного беспорядка в ваше приложение, но кто-то всегда может удалить его (или закомментировать), если он хочет, я думаю. Мне действительно хотелось бы, чтобы в вашем классе был только метод test (), который автоматически компилировался для сборок выпуска - мне нравится, что мой тестовый метод находится в том же файле, что и мой код ...

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

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

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

Между прочим, когда я работал над довольно большим проектом Ruby / Rails, у нас был очень высокий% тестового покрытия. Мы реорганизовали основной, центральный класс модели на два класса. Это заняло бы у нас два дня, но с учетом всех тестов, которые нам потребовались для рефакторинга, это закончилось ближе к двум неделям. Тесты НЕ полностью бесплатны.

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

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

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

  1. написать один минимальный тест
  2. пройти тест, написав минимально необходимый производственный код
  3. напишите следующий тест, который не удастся
  4. пройти все существующие тесты, изменив существующий производственный код самым простым способом
  5. реорганизовать код (как тестовый, так и производственный!), чтобы он не содержал дублирования и был выразительным
  6. продолжайте с 3. до тех пор, пока вы не перестанете думать о другом разумном тесте

Один цикл (3-5) обычно занимает всего пару минут. Используя этот метод, вы фактически эволюционировать разрабатываете, пока вы пишете тесты и производственный код параллельно. Здесь вообще не так уж много начального дизайна.

По вопросу о том, что это «необходимо» - нет, очевидно, нет. Было бесчисленное количество успешных проектов без TDD. Но есть убедительные доказательства того, что использование TDD обычно приводит к значительно более высокому качеству, часто без отрицательного воздействия на производительность. И это тоже весело!

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

Сейчас так много ответов, и все они разные. Это полностью соответствует действительности. Все делают по-разному. Я думаю, что существует огромное недоразумение в отношении модульного тестирования. Мне кажется, что люди слышали о TDD и сказали, что это хорошо. Затем они начали писать модульные тесты, не понимая, что такое TDD на самом деле. Они только что получили часть «о да, мы должны написать тесты», и они согласны с этим. Они также слышали о том, что «вы должны сначала написать свои тесты», но они не относятся к этому серьезно.

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

Самое смешное, если они начнут спорить: «Я не убежден в том, что это первое испытание, но я никогда не делал этого таким образом» ... отлично ...

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

Другие вопросы по теме