Проблема возникает при выполнении TDD. После нескольких тестовых прохождений типы возвращаемых данных некоторых классов / модулей меняются. В статически типизированном языке программирования, если предыдущий смоделированный объект использовался в тестах какого-либо другого класса и не был изменен для отражения изменения типа, тогда произойдут ошибки компиляции.
Однако для динамических языков изменение типов возврата может не обнаруживаться, и тесты другого класса все равно будут проходить. Конечно, могут быть интеграционные тесты, которые в дальнейшем не пройдут, но модульные тесты будут ошибочно проходить. Есть ли способ, как этого избежать?
Обновление с тривиальным образцом (на некоторых выдуманных языках) ...
Версия 1:
Calc = {
doMultiply(x, y) {return x * y}
}
//.... more code ....
// On some faraway remote code on a different file
Rect = {
computeArea(l, w) {return Calc.doMultipy(x*y)}
}
// test for Rect
testComputeArea() {
Calc = new Mock()
Calc.expect(doMultiply, 2, 30) // where 2 is the arity
assertEqual(30, computeArea)
}
Теперь о версии 2:
// I change the return types. I also update the tests for Calc
Calc = {
doMultiply(x, y) {return {result: (x * y), success:true}}
}
... Rect затем выдаст исключение во время выполнения, но тест все равно будет успешным.
источник
class X
, а в том, отclass Y
каких тестов зависитX
и, таким образом, их тестируют по контракту, отличному от того, с которым он работает в производстве.Ответы:
В определенной степени это только часть затрат на ведение бизнеса с динамическими языками. Вы получаете большую гибкость, иначе известную как «достаточно веревки, чтобы повеситься». Будь осторожен с этим.
Для меня проблема заключается в использовании других методов рефакторинга, чем в статически типизированном языке. В статическом языке вы частично заменяете типы возвращаемых данных, чтобы вы могли «опираться на компилятор», чтобы найти места, которые могут сломаться. Это безопасно и, вероятно, безопаснее, чем модифицировать возвращаемый тип на месте.
На динамическом языке вы не можете этого сделать, поэтому гораздо безопаснее изменить тип возвращаемого значения, чем заменить его. Возможно, вы измените его, добавив новый класс в качестве члена, для классов, которые в этом нуждаются.
источник
Если ваши изменения кода и тесты все еще проходят, то есть либо что - то не так с вашими тестами (то есть вам не хватает утверждение), или код не реально изменить.
Что я имею в виду под этим? Ну, ваши тесты описывают контракты между частями вашего кода. Если в контракте указано «возвращаемое значение должно быть итеративным», то изменение возвращаемого значения, скажем, массива в список, на самом деле не является изменением контракта и, следовательно, не обязательно приведет к провалу теста.
Для того , чтобы не пропустить утверждения, вы можете использовать такие инструменты, как анализ покрытия коды (он не скажет вам , какие части вашего кода тестирует, но это будет вам сказать , что детали определенно не тестировались), цикломатическая сложность и сложность NPath (которые дают вам нижнюю границу на ряд утверждений , необходимых для достижения полного C1 и C2 покрытия кода) и мутации тестировщиков (которые INJECT мутации в вашем коде , такие как поворот
true
кfalse
, отрицательные числа в положительную, объекты в иnull
т.д. , и проверить , что делает тесты провальными).источник