Как использовать TDD, если исправление связано с изменением сигнатуры тестируемого метода?

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

Рассмотрим следующую сигнатуру метода:

string RemoveTokenFromString (string delimited, string token)

Как следует из названия, этот метод удаляет все экземпляры token из delimited и возвращает результирующую строку.

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

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

Что мне тогда делать? Если я исправлю ошибку, это заставит меня изменить модульный тест - будет ли это «правильной» методологией TDD?


person jpoh    schedule 08.04.2009    source источник


Ответы (7)


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

//Up front
[Test]
public void should_remove_correct_token_from_string()
{
  var text = "do.it.correctly..";
  var expected = "doitcorrectly";
  Assert.AreEqual(StaticClass.RemoveTokenFromString(text, "."), expected);
}

//After finding that it doesn't do the right thing
//Delete the old test and *design* a new function that
//Does what you want through a new test
//Remember TDD is about design, not testing!
[Test]
public void should_remove_correct_token_from_string()
{
  var text = "do.it.correctly..";
  var expected = "doitcorrectly";
  Assert.AreEqual(
      StaticClass.RemoveTokenFromString(
          text,
          ".",
          System.Text.Encoding.UTF8), expected);
}

//This will force you to add a new parameter to your function
//Obviously now, there are edge cases to deal with your new parameter etc.
//So more test are required to further design your new function
person Jim Burger    schedule 08.04.2009

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

В TDD тесты на самом деле не тесты, а примеры. А утверждения - это не утверждения, это ожидания. И вы имеете дело не с юнитами, вы имеете дело с поведением. BDD просто так их называет. (Примечание: BDD развивался с тех пор, как был впервые изобретен, и теперь он включает в себя вещи, которые не являются частью TDD, но первоначальным намерением было просто «многие люди делают TDD неправильно, поэтому используйте разные слова, чтобы помочь им сделать это правильно». )

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

person Jörg W Mittag    schedule 08.04.2009

Будь проще.

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

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

person Jon Limjap    schedule 08.04.2009

Здесь может помочь рефакторинг под названием Добавить параметр.

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

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

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

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

Значение параметра по умолчанию также может помочь, если оно доступно.

person philant    schedule 08.04.2009

Красный, зеленый, рефакторинг.

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

person Eugene Yokota    schedule 08.04.2009

Я бы сказал, не беспокойтесь о «правильном» / «правильном» способе ... все, что поможет вам быстрее приблизиться к решению.

Если вы обнаружите, что вам нужно принять дополнительный параметр,

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

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

  • написать новую перегрузку с добавленным параметром
  • Переместите код старого метода в новую перегрузку
  • Сделайте старое реле перегрузки или делегируйте новую перегрузку с некоторым значением по умолчанию для нового параметра
  • Теперь вы можете вернуться к текущей задаче и сделать новый тест зеленым.
  • Если вам больше не нужна старая перегрузка, удалите ее и исправьте возникшие ошибки компиляции.
person Gishu    schedule 08.04.2009

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

person Bhushan Bhangale    schedule 08.04.2009