Когда не / писать тесты до реализации?
Я не уверен, как работает "сначала тесты", и я хотел бы услышать аргументы о том, когда и почему можно было бы использовать этот подход.
Я слышал, что часто рекомендуется писать тесты и макетировать вещи, прежде чем писать одну строчку реализации. Тем не менее, я не могу не думать, что это подходит не для каждой ситуации. Например, скажем, я делаю прототип, и я не уверен, как все будет работать еще. Поэтому я просто начинаю находить примеры каждого необходимого мне шага и добавляю их в свой код. В конце у меня есть доказательство моей теории, и это не заняло много времени. Это по сути "мой тест". Это не юнит-тест, а тест (скорее всего, это консольное приложение).
Это в значительной степени то, как я работаю. Я думаю о том, что хочу сделать, и пытаюсь это сделать. Если это сработает, я в конце концов вернусь и напишу модульные тесты, чтобы можно было перехватить регрессию. Это отличается от того, что вы "должны делать"?
7 ответов
Главное правило: сначала делайте самые рискованные вещи.
Выполнение тестовых примеров сначала подразумевает, что самая рискованная часть кодирования - это недопонимание и неправильное понимание интерфейсов и поведения создаваемых объектов.
Для многих проектов это вполне может быть правдой, и TDD очень подходит в таких случаях.
Однако во многих проектах это не так, и применение TDD в таких случаях является плохим выбором.
Если ваш самый высокий риск заключается в удобстве использования, прекратите суетиться с юнит-тестами и сделайте некоторое прототипирование пользовательского интерфейса.
Если ваш самый высокий риск - производительность, сначала создайте несколько прототипов производительности и не беспокойтесь об интерфейсах.
Этот список можно продолжить.
Выполнение рискованных предметов в первую очередь имеет много преимуществ:
Проекты, которые неизбежно обречены, рано умирают, прежде чем тратятся многие ресурсы.
Проекты, которые находятся в беде, но могут быть спасены, привлекают внимание к управлению проектами рано, когда это может принести пользу.
Деловая сторона вашей организации будет ценить проект выше, когда у него низкий риск неудачи; есть меньше шансов, что он будет отменен рано без необходимости.
"Я слышал, что часто рекомендуется писать тесты и макетировать вещи перед написанием одной строки реализации… В конце концов я возвращаюсь и пишу модульные тесты… Это отличается от того, что вы" должны делать "?"
Поскольку вы начали с ответа на свой вопрос, то вы на самом деле не задаете этот вопрос, не так ли?
Есть много причин, почему люди отвечают на свои вопросы. Иногда это способ спорить.
Это позволяет людям сказать: "Я не спорю, я просто спрашиваю, почему это так неправильно".
Цель - сначала проверить. Вот как это работает.
Допустим, я делаю прототип и пока не уверен, как все будет работать.
Я, однако, знаю одну вещь. Что он должен делать.
Запишите конкретный пример того, что он должен делать. Конкретные, конкретные входы и выходы.
Это контрольный пример. Я сделал это первым. Могу ли я оформить это как юнит-тест? Возможно нет. Однако я начал с приемочного теста.
Теперь я могу разбить проблему на части.
Поэтому я просто начинаю находить примеры каждого шага, который мне нужен.
Для каждого примера того, что мне нужно, я записываю, что входит и что выходит из шага.
Это тестовые случаи. Я сделал их первым. Во многих случаях я могу оформить их как модульные тесты.
Получив тест, я возвращаюсь к примеру каждого шага и добавляю его в свой код.
Я сделал тестирование, затем кодирование. Я не делал ВСЕ тестирования до ЛЮБОГО кодирования. Сначала я проводил тестирование, но не сумасшедшим способом "все тесты без кода". Я сделал это в пошаговом тесте - немного кода - немного. Но сначала все было проверено.
Это просто, ответ во время прототипирования. На этом этапе вы недостаточно хорошо понимаете систему, в которой построено ваше здание, чтобы правильно проводить тестирование, и в любом случае хорошая практика говорит, что код прототипа должен быть отбрасываемым, поэтому тестирование не даст вам никаких реальных преимуществ на этом этапе. Но понимание, основанное на прототипировании, поможет вам, так что вы сможете провести эффективное тестирование, как только войдете в производство.
Так что да, ваш подход верен, если вы делаете тест после прототипов
Даже когда вы пишете одноразовый прототип, все равно может быть полезно подумать о том, что на самом деле будет делать прототип, и начать с тестов, которые подтверждают, что он делает. Обеспечение возможности тестирования прототипа также определит подход к решению.
Затем, когда код выбрасывается, у вас все еще есть тесты.
У меня также возникают проблемы с тестированием прототипов, но когда мне удавалось это сделать, я всегда был рад этому.
Я думаю, что ваш подход не тестировать шип / прототип просто отлично. Но две идеи:
После того, как вы закончили свой прототип и знаете, что делаете, либо выбросьте его и заново внедрите его, либо напишите тесты для кода, который вы уже написали.
если у вас больше практики с модульными тестами, вы можете быстрее создать свой прототип в тесте, чем создать консольное приложение. Я не имею в виду создание тестов и отдельного класса с идеей, я имею в виду исследовать код прямо в методе тестирования. Я делал это несколько раз, и я был очень счастлив с этим. Когда я изучаю новый API или даже новый язык, тест дает мне самый быстрый цикл обратной связи для попытки эксперимента. Затем, когда код работает, я могу выделить его в отдельный метод / класс, чтобы он стал частью реальной системы.
Не существует единого "правильного способа сделать это". Тем не менее, я думаю, что тестовая разработка (TDD) поможет в вашем случае. Я считаю, что написание тестов сначала помогает сформировать API и делает код чище. Когда вы сначала пишете тесты, вы сначала думаете о том, как будет вызываться код (интерфейс или "что это должно делать"), прежде чем думать о реализации ("как мне это сделать").
Например, представьте себе создание модуля CRM. Вы можете подумать, что первое, что нужно сделать, это получить клиента, который потратил больше всего денег. Итак, вы бы написали тест:
Assert.AreEqual (Customer1, crm.GetMostValuableCustomer (), "самый ценный клиент не так, как ожидалось");
Затем вы можете добавить что-то вроде:
Assert.AreEqual (новый клиент [] {клиент1, клиент2, клиент3}, crm.GetCustomerByValue(), "GetCustomersByValue() не так, как ожидалось");
Итак, дело в том, что вы думаете о коде с другой точки зрения (как потребитель, а не как производитель). Я верю, что это помогает мне писать более чистый код, и мне не нужно потом возвращаться и создавать регрессионные тесты позже. Хотелось бы, чтобы у меня был лучший пример, но, надеюсь, вы сможете увидеть, как работа с этим методом действительно может помочь вам на этапе создания прототипа.
Я обнаружил, что написание тестов сначала не работает так хорошо, когда я все еще строю "историю" своего кода. Трудно писать тесты, когда я не уверен, как выглядят интерфейсы. Я мог бы написать код заглушки, чтобы конкретизировать классы и интерфейсы, не думая о тестах. Но я стараюсь пройти тесты как можно быстрее. Я считаю, что это помогает, если я делаю заметки о том, что я буду тестировать, когда создаю дизайн, а затем, когда мой дизайн становится более устойчивым, я возвращаюсь к своим заметкам и делаю эти тесты первыми. Обычно это означает, что код реализации и модульного теста срастается, ни один, ни другой.