Я довольно новичок в TDD, и у меня возникают проблемы при создании моего первого теста, когда он предшествует любому из кода реализации. Без какой-либо основы для кода реализации я могу написать свой первый тест, как бы мне этого ни хотелось, но он всегда кажется испорченным моим подходом к проблеме Java / OO.
Например, в моем Github ConwaysGameOfLifeExample первый тест, который я написал (rule1_zeroNeighbours), я начал с создания объекта GameOfLife, который еще не был реализован; вызывал метод set, который не существует, метод step, который не существовал, метод get, который не существовал, а затем использовал assert.
Тесты развивались, когда я писал больше тестов и проводил рефакторинг, но изначально это выглядело примерно так:
@Test
public void rule1_zeroNeighbours()
{
GameOfLife gameOfLife = new GameOfLife();
gameOfLife.set(1, 1, true);
gameOfLife.step();
assertEquals(false, gameOfLife.get(1, 1));
}
Это было странно, так как я заставлял проект реализации основываться на том, как я решил на этом раннем этапе написать этот первый тест.
Насколько вы понимаете, TDD это нормально? Кажется, я следую принципам TDD / XP, так как мои тесты и реализация со временем эволюционировали благодаря рефакторингу, и поэтому, если бы этот первоначальный проект оказался бесполезным, его можно было бы изменить, но мне кажется, что я навязываю направление Решение, начав таким образом.
Как еще люди используют TDD? Я мог бы пройти через итерацию рефакторинга, начав без объекта GameOfLife, только примитивов и статических методов, но это кажется слишком надуманным.
источник
Ответы:
Я думаю, что это ключевой момент в вашем вопросе: желательно ли это или нет, зависит от того, склоняетесь ли вы к идее codeninja о том, что вы должны разрабатывать заранее, а затем использовать TDD для заполнения реализации, или к мысли Дуррона о том, что тесты должны участвовать в вытесняя дизайн, а также реализацию.
Я думаю, какой из них вы предпочитаете (или где вы попадаете в середину) - это то, что вам нужно открыть для себя в качестве предпочтения. Полезно понимать плюсы и минусы каждого подхода. Их, вероятно, много, но я бы сказал, что основными из них являются:
Pro Upfront Design
Pro Test-Driving Design
Построив свою реализацию на клиентском программном коде (ваших тестах), вы получите YAGNI-приверженность практически бесплатно, если только вы не начнете писать ненужные тестовые примеры. В более общем смысле вы получаете API, который разработан с учетом его использования потребителем, что в конечном итоге является тем, что вам нужно.
Идея нарисовать кучу диаграмм UML перед написанием любого кода, а затем просто заполнить пробелы, хороша, но редко реалистична. В «Полном коде» Стива Макконнелла дизайн, как известно, описывается как «злая проблема» - проблема, которую вы не можете полностью понять, если сначала хотя бы частично ее не решить. Соедините это с тем фактом, что сама проблема может измениться в результате изменения требований, и эта модель дизайна начинает казаться немного безнадежной. Тестовое вождение позволяет вам просто откусить один кусок работы за раз - в дизайне, а не только за реализацию - и знать, что, по крайней мере, в течение срока службы от красного до зеленого эта задача все еще будет актуальной и актуальной.
Что касается вашего конкретного примера, как говорит Дуррон, если вы использовали подход, заключающийся в том, чтобы выкроить дизайн, написав простейший тест, потребляя минимально возможный интерфейс, вы, вероятно, начнете с более простого интерфейса, чем тот, что был в вашем фрагменте кода. ,
источник
Чтобы написать тест в первую очередь, вы должны разработать API, который вы затем собираетесь реализовать. Вы уже начали не с той ноги, написав свой тест для создания всего
GameOfLife
объекта и используя его для реализации своего теста.Из практического юнит-тестирования с JUnit и Mockito :
Ваш тест не делает много попыток разработать API. Вы настроили систему с состоянием, в которой вся функциональность содержится во внешнем
GameOfLife
классе.Если бы я написал это приложение, я бы подумал о том, что я хочу построить. Например, я мог бы создать
Cell
класс, написать тесты для этого, прежде чем перейти к более крупному приложению. Я бы, конечно, создал класс для структуры данных «бесконечный во всех направлениях», который требуется для правильной реализации Conway, и протестировал бы это. Как только все это будет сделано, я подумаю о написании общего класса, который имеетmain
метод и так далее.Легко замаскировать шаг «написать тест, который провалился». Но написание проваливающегося теста, который работает так, как вы хотите, является ядром TDD.
источник
boolean
, такой дизайн, безусловно, будет хуже для производительности. Разве он должен быть расширяемым в будущем для других клеточных автоматов с более чем двумя состояниями?Там разные школы мысли об этом.
Некоторые говорят: тест не компилируется - это ошибка - иди исправь, напиши наименьший доступный производственный код.
Некоторые говорят: все в порядке, чтобы написать тест, сначала проверить, сосет ли он (или нет), а затем создать недостающие классы / методы.
При первом подходе вы действительно находитесь в цикле красно-зеленого-рефактора. Со вторым у вас есть немного более широкий обзор того, чего вы хотите достичь.
Вам решать, каким образом вы будете работать. ИМХО оба подхода верны.
источник
Даже когда я реализую что-то «взломать вместе», я все равно придумываю классы и этапы, которые будут задействованы во всей программе. Итак, вы продумали это и записали эти мысли о дизайне в первую очередь как тест - это здорово!
Теперь продолжайте выполнять обе реализации для выполнения этого начального теста, а затем добавьте больше тестов для улучшения и расширения проекта.
Что может помочь вам, это использовать Cucumber или подобное для написания ваших тестов.
источник
Прежде чем вы начнете писать свои тесты, вы должны подумать о том, как спроектировать вашу систему. Вы должны потратить значительное количество времени на этапе проектирования. Если вы сделали это, вы не получите эту путаницу из-за TDD.
TDD - это просто ссылка на подход к разработке : TDD
1. Добавьте тест
2. Запустите все тесты и посмотрите, не прошел ли новый тест
3. Напишите некоторый код
4. Запустите тесты
5. Код рефакторинга
6. Повторите
TDD поможет вам охватить все необходимые функции, которые вы запланировали, прежде чем приступить к разработке программного обеспечения. ссылка: Преимущества
источник
По этой причине я не люблю тесты системного уровня, написанные на Java или C #. Посмотрите на SpecFlow для c # или один из основанных на Cucumber тестовых фреймворков для Java (возможно, JBehave). Тогда ваши тесты могут выглядеть примерно так.
И вы можете изменить свой объектный дизайн без необходимости менять все системные тесты.
(«Нормальные» юнит-тесты хороши при тестировании отдельных классов.)
Каковы различия между средами BDD для Java?
источник