Что вы делаете, когда пишете тест, и вы попадаете в точку, где вам нужно пройти тест, и вы понимаете, что вам нужен дополнительный фрагмент функциональности, который должен быть разделен на его собственную функцию? Эта новая функция также должна быть протестирована, но цикл TDD говорит: «Провести тест неудачно, сделать так, чтобы он прошел рефакторинг». Если я нахожусь на этапе, когда я пытаюсь выполнить свой тест, я не должен уходить и начинать другой неудачный тест, чтобы протестировать новую функциональность, которую мне нужно реализовать.
Например, я пишу точечный класс, который имеет функцию WillCollideWith ( LineSegment ) :
public class Point {
// Point data and constructor ...
public bool CollidesWithLine(LineSegment lineSegment) {
Vector PointEndOfMovement = new Vector(Position.X + Velocity.X,
Position.Y + Velocity.Y);
LineSegment pointPath = new LineSegment(Position, PointEndOfMovement);
if (lineSegment.Intersects(pointPath)) return true;
return false;
}
}
Я писал тест для CollidesWithLine, когда понял, что мне понадобится функция LineSegment.Intersects ( LineSegment ) . Но должен ли я просто остановить то, что я делаю в моем цикле испытаний, чтобы создать новую функциональность? Кажется, это нарушает принцип «красный, зеленый, рефакторинг».
Должен ли я просто написать код, который обнаруживает, что lineSegments Intersect внутри функции CollidesWithLine и рефакторинг его после того, как он работает? Это сработало бы в этом случае, так как я могу получить доступ к данным из LineSegment , но что делать в случаях, когда такие данные являются частными?
источник
В цикле TDD:
На этапе «сделать тестовый проход» вы должны написать простейшую реализацию, которая сделает тестовый проход . Чтобы пройти тест, вы решили создать нового соавтора, который будет обрабатывать недостающую логику, потому что, возможно, было слишком много работы для того, чтобы поместить в ваш точечный класс тест на прохождение теста. Вот в чем проблема. Я полагаю, что тест, который вы пытались пройти, был слишком большим шагом . Поэтому я думаю, что проблема заключается в самом вашем тесте, вы должны удалить / прокомментировать этот тест и найти более простой тест, который позволит вам сделать шаг вперед, не вводя часть LineSegment.Intersects (LineSegment). Если у вас есть этот тест, вы можете затем рефакторингваш код (здесь вы будете применять принцип SRP), переместив эту новую логику в метод LineSegment.Intersects (LineSegment). Ваши тесты все равно пройдут, потому что вы не изменили своего поведения, а просто переместили некоторый код.
На вашем текущем дизайнерском решении
Но для меня у вас есть более серьезная проблема в дизайне: вы нарушаете принцип единой ответственности . Роль Точки ... быть точкой, вот и все. Нет смысла в том, чтобы быть точкой, это просто значение x и y. Точки являются типами значений . Это то же самое, что и для сегментов, сегменты представляют собой типы значений, состоящие из двух точек. Они могут содержать немного «сообразительности», например, чтобы вычислить их длину на основе положения их точек. Но это все.
Теперь решить, сталкиваются ли точка и отрезок, - это отдельная ответственность. И, безусловно, слишком много работы для точки или сегмента, чтобы справиться самостоятельно. Он не может принадлежать классу Point, потому что иначе Point будет знать о сегментах. И он не может принадлежать сегментам, потому что сегменты уже несут ответственность за заботу о точках внутри сегмента и, возможно, также за вычисление длины самого сегмента.
Таким образом, эта ответственность должна принадлежать другому классу, такому как, например, «PointSegmentCollisionDetector», который будет иметь такой метод:
bool AreInCollision (точка p, сегмент s)
И это то, что вы будете тестировать отдельно от точек и сегментов.
Приятно то, что теперь у вас может быть другая реализация вашего детектора столкновений. Так что было бы легко, например, сравнить свой игровой движок (я полагаю, вы пишете игру: p), переключив метод обнаружения столкновений во время выполнения. Или сделать некоторые визуальные проверки / эксперименты во время выполнения между различными стратегиями обнаружения столкновений.
На данный момент, внедряя эту логику в свой класс Point, вы блокируете вещи и возлагаете слишком большую ответственность на класс Point.
Надеюсь, это имеет смысл,
источник
Самое простое, что можно сделать в режиме TDD, - это извлечь интерфейс для LineSegment и изменить параметр метода, чтобы он воспринимал интерфейс. Затем вы можете смоделировать входной отрезок и кодировать / тестировать метод Intersect независимо.
источник
С jUnit4 вы можете использовать
@Ignore
аннотацию для тестов, которые вы хотите отложить.Добавьте аннотацию к каждому методу, который вы хотите отложить, и продолжайте писать тесты для требуемой функциональности. Обведите обратно, чтобы рефакторинг старых тестовых случаев позже.
источник