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

Я пытаюсь использовать TDD для написания игры в нарды на C++ с использованием VS 2010.

Я настроил CxxTest для написания тестовых случаев.

Первый класс для тестирования

class Position
{
public:
...
...
bool IsSingleMoveValid(.....)
...
...
}

Я хотел бы написать тест для функции IsSingleMoveValid (), и я думаю, что тест должен доказать, что функция работает правильно. К сожалению, есть очень много случаев для тестирования, и даже если я протестирую несколько случаев, некоторые могут сбежать.

Что ты предлагаешь? Как TDD справляется с этими проблемами?

5 ответов

Решение

Несколько рекомендаций:

  1. Тестируйте регулярные случаи. В вашей проблеме: проверяйте законные ходы, которые вы ЗНАЕТЕ, действительны. Вы можете либо пойти простым путем и иметь только несколько тестовых случаев, либо вы можете написать цикл, генерирующий все возможные законные шаги, которые могут возникнуть в вашем приложении, и протестировать их все.
  2. Тест граничных случаев. Это не совсем применимо к вашей задаче, но для тестирования простых числовых функций вида f(x) откуда ты это знаешь x должен лежать в диапазоне [x_min, x_max), вы бы обычно также проверить f(x_min-1), f(x_min), f(x_max-1), f(x_max), (Это может быть актуально для настольных игр, если у вас есть внутреннее представление доски с краем переполнения вокруг него)
  3. Проверьте известные ошибки. Если вы когда-либо сталкивались с легальным ходом, который не признается вашим IsSingleMoveValid()Вы добавляете это в качестве тестового примера и затем исправляете свой код. Полезно сохранять такие тестовые случаи для защиты от будущих регрессий (некоторые будущие добавления / модификации кода могут повторно представить эту ошибку, и тест ее поймает).

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

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

Если вы пишете тесты, то проще всего сломать IsSingleMoveValid функционировать в меньшие функции и тестировать их индивидуально.

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

Как вы можете видеть в Википедии, TDD - Test Driven Development - это сначала написание теста.

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

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

Как уже говорилось, когда функция слишком сложна, наступает время рефакторинга!

Я настоятельно рекомендую вам книгу " Рефакторинг - улучшение дизайна существующего кода" Мартина Фаулера с участием Кента Бека и других. Это учебник и справочник, что делает его очень ценным, на мой взгляд.

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

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

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

Следовательно, вам нужно начать с написания теста для всех случаев.

если есть большое, скажем, ради обсуждения, что у вас есть счетный набор возможных вариантов для тестирования (т. е. добавьте (n,m) == n+m для всех n и m целых чисел), но ваш фактический код действительно прост; вернуть n+m. Это, конечно, тривиально, но не стоит упускать из виду: вам не нужно тестировать все возможные ходы на доске, TDD стремится, чтобы ваши тесты охватывали весь код (т. Е. Тесты выполняют все ветви if в ваш код), не обязательно все возможные значения или комбинации состояний (которые экспоненциально велики)

проект с 80-90% покрытия строк означает, что ваши тесты используют 9 строк из каждых 10 строк вашего кода. В общем случае, если в вашем коде есть ошибка, это в большинстве случаев будет подтверждено при прохождении определенного пути кода.

Другие вопросы по тегам