Как подойти к юнит-тестированию и TDD (используя python + Nose)

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

  1. Идея TDD заключается в том, что модульные тесты пишутся до кода, который они тестируют. Модульный тест должен тестировать небольшие части кода (например, функции), которые для целей теста являются автономными и изолированными. Однако мне кажется, что это сильно зависит от реализации. Во время реализации или во время последующего исправления ошибки может возникнуть необходимость абстрагировать часть кода в новую функцию.Должен ли я затем пройти все свои тесты и смоделировать эту функцию, чтобы изолировать их? Неужто при этом есть опасность внесения в тесты новых багов, и тесты уже не будут тестировать точно такую ​​же ситуацию?

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

  3. Часто, однажды изолированные, модульные тесты кажутся просто повторяющими функцию. Например. если есть простая функция, которая складывает два числа, то тест, вероятно, будет выглядеть примерно так: assert add(a, b) == a + b. Поскольку реализация просто return a + b, какой смысл в тесте? Гораздо более полезным тестом было бы увидеть, как функция работает в системе, но это идет вразрез с модульным тестированием, поскольку оно больше не является изолированным.

  4. Мой вывод таков: модульные тесты хороши в некоторых ситуациях, но не везде, и что системные тесты в целом более полезны. Подход, который это подразумевает, заключается в том, чтобы сначала написать системные тесты, а затем, если они не пройдут, изолировать части системы в модульные тесты, чтобы точно определить сбой. Проблема с этим, очевидно, заключается в том, что не так просто проверить крайние случаи. Это также означает, что разработка не полностью управляется тестами, поскольку модульные тесты пишутся только по мере необходимости.

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

  1. Следует ли везде использовать модульные тесты, какими бы маленькими и простыми ни были функции?
  2. Как быть с изменением реализации? т.е. должна ли реализация тестов постоянно меняться, и не снижает ли это их полезность?
  3. Что делать, когда тест становится сложнее кода, который его тестирует?
  4. Всегда ли лучше начинать с юнит-тестов или лучше начинать с системных тестов, которые в начале разработки написать намного проще?
7
задан aquavitae 11 March 2012 в 10:54
поделиться