Подтвердить что ты не робот

Насколько строго я должен быть в "простейшем, что можно было бы работать" при выполнении TDD

Для TDD вы должны

  • Создать тест, который не работает
  • Простейшая вещь, которая могла бы сработать, чтобы пройти тест
  • Добавьте несколько вариантов теста и повторите
  • Рефакторинг при появлении шаблона

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

Например, я обрабатываю файл, и если он не соответствует определенному формату, я должен бросить InvalidFormatException

Итак, мой первый тест:

@Test 
void testFormat(){
    // empty doesn't do anything nor throw anything
    processor.validate("empty.txt"); 
    try {
        processor.validate("invalid.txt");
        assert false: "Should have thrown InvalidFormatException";
    } catch( InvalidFormatException ife ) {
        assert "Invalid format".equals( ife.getMessage() );
    }
 }

Я запускаю его, и он терпит неудачу, потому что он не генерирует исключение.

Итак, следующее, что приходит мне на ум, - это "Простейшая вещь, которая могла бы работать", поэтому я:

public void validate( String fileName ) throws InvalidFormatException {
    if(fileName.equals("invalid.txt") {
        throw new InvalidFormatException("Invalid format");
    }
}

Doh!! (хотя реальный код немного сложнее, я обнаружил, что сам делал что-то подобное несколько раз)

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

Q: Я беру слишком буквальный материал "Делают простейшую вещь..."?

4b9b3361

Ответ 1

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

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

Ответ 2

Конечно, ваша интерпретация правила слишком буквальна. Вероятно, это должно звучать так: "Сделайте простейшую потенциально полезную вещь..."

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

Ответ 3

Я тоже новичок в TDD, борющийся с этим вопросом. Во время исследования я нашел этот пост в блоге Роя Ошерова, который был первым и единственным конкретным и осязаемым определением "самой простой вещи, которая могла бы работать" что я нашел (и даже Рой признал, что это только начало).

В двух словах, Рой говорит:

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

"Могу ли я реализовать одно и то же решение таким образом, что это..."

  • ".. Более жестко закодированный.."
  • ".. Ближе к началу метода я написал его в.."
  • ". Меньше с отступом (как можно меньше" областей ", таких как ifs, loop, try-catch).
  • ".. короче (буквально меньше символов для записи), но все еще читаемый.."

"... и все еще пройти все тесты?"

Если ответ на один из них "да", то сделайте это и посмотрите, все тесты все еще проходят.

Ответ 4

Много комментариев:

  • Если проверка "empty.txt" вызывает исключение, вы ее не поймаете.

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

  • Я не вижу никаких признаков модульного тестирования. Может быть, я скучаю по ним? Но просто использование assert не будет масштабироваться для более крупных систем. Когда вы получаете результат от проверки, у вас должен быть способ объявить платформе тестирования, что данный тест с заданным именем преуспел или не удался.

  • Я встревожен тем, что проверка имени файла (в отличие от содержимого) представляет собой "проверку". На мой взгляд, это слишком просто.

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

Ответ 5

Вы пропустили пункт № 0 в своем списке: знаете, что делать. Вы говорите, что обрабатываете файл для целей проверки. После того, как вы указали, что означает "проверка" (подсказка: сделайте это, прежде чем писать какой-либо код), вы можете лучше понять, как: a) написать тесты, которые, ну, протестировать спецификацию, как реализовано, и b) написать простейшую вещь.

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

Ответ 6

Одно замечание для будущих учеников TDD - мантра TDD на самом деле не включает "Делайте простейшую вещь, которая могла бы работать". Kent Beck TDD Book имеет только 3 шага:

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

Хотя фраза "Простейшая вещь..." часто приписывается Уорду Каннингему, он действительно задал вопрос "Какая самая простая вещь, которая могла бы быть работа?" , но этот вопрос позже превратился в команду, которую, по мнению Уорда, может смутить, скорее, помощь.

Изменить: я не могу рекомендовать читать Beck TDD Book достаточно сильно - ему нравится иметь сеанс сопряжения с самим мастером, давая вам идеи и мысли о процессе разработки, управляемом тестированием.

Ответ 7

Как метод должен делать только одну вещь, один тест должен проверять только одну вещь (поведение). Чтобы обратиться к приведенному примеру, я бы написал два теста, например, test_no_exception_for_empty_file и test_exception_for_invalid_file. На втором, действительно, может быть несколько тестов - по одному на вид недействительности.

Третий шаг процесса TDD должен интерпретироваться как "добавить новый вариант теста", а не "добавить новый вариант теста". Действительно, a unit test должен быть атомарным (протестируйте только одно) и обычно следует тройной шаблон A: Arrange - Act - Assert. И очень важно проверить, что тест сначала потерпел неудачу, чтобы убедиться, что он действительно что-то тестирует.

Я бы также отделил ответственность за чтение файла и проверку его содержимого. Таким образом, тест может передать буфер функции validate(), и тесты не должны читать файлы. Обычно модульные тесты не имеют доступа к файловой системе, поэтому это замедляет работу.