Что делать, если стандарты кодирования проекта конфликтуют с охватом кода модульного теста? - PullRequest
7 голосов
/ 04 декабря 2011

Я работаю над личным проектом для обучения, и в то же время, чтобы реализовать приличный объем кода.Частью этого образования и превращения его в приличную часть кода является модульное тестирование.Недавно я погрузился в PHPUnit и его инструменты покрытия кода.

Я столкнулся с ситуацией с конкретной реализацией, когда используемый стандарт кодирования приводит к потере покрытия кода.В этом конкретном случае нарушение используемого стандарта кодирования вызывает скачок покрытия кода с 88% до 94%.

В методе у меня есть 2 строки, которые выглядят следующим образом

    // .. some data validation stuff
    trigger_error('Error validating the stuff', E_USER_WARNING);
}

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

Если я сделаю

    // .. some data validation stuff
    trigger_error('Error validating the stuff', E_USER_WARNING);}

, я получу скачок кода на 6%.Я попытался установить PHPUnit_Framework_Error_Warning::$enabled на false, но затем я получаю уродливое, ожидаемое сообщение об ошибке в моем терминале, поскольку я хочу, чтобы этот проект в конечном итоге использовался людьми, кроме меня, сообщения об ошибках в модульных тестах неприемлемы.Кроме того, я действительно хотел бы, чтобы мои стили кодирования были реализованы последовательно.Нарушение стиля кода, вероятно, выскочило бы при дальнейшем прочтении кода, а это значит, что мне также пришлось бы добавить страшный комментарий, объясняющий, почему скобки были перемещены ... вероятно, в нескольких местах.

Я полагаю, мойВопрос (ы):

  1. Существует ли параметр для PHPUnit, который позволил бы использовать 1TBS и по-прежнему покрываться тестом, генерирующим исключение или вызывающим ошибку, непосредственно перед }?
  2. Важнее ли следовать стандарту кодирования или увеличить охват кода?(Хотя на самом деле толчок - это просто переводчик, перебирающий лишние })

Ответы [ 4 ]

7 голосов
/ 04 декабря 2011

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

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

3 голосов
/ 05 декабря 2011

К первоначальному вопросу:

Ваши правила кодирования не должны ограничиваться 100% охватом кода. Если вы напишете все приложение в одну строку, вы получите 100%, но только потому, что PHPUnit / xDebug в настоящее время сообщает LINE покрытие не STATEMENT покрытие .


Для меня проблемапод рукой еще один:

У вас есть метод, который безоговорочно вызывает ошибку в конце.

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

"Does trigger error get into the way of having 100% code coverage / complete tests"

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

Поэтому при использовании trigger_error он сводится к:

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

И если у вас есть возвращаемое значение, вы можете написать значимые тесты для этого метода.

Один тестовый случай, который проверяетдля trigger_error и одного тестового случая (который вызывает метод с подавлением ошибок), который утверждает возвращаемое значение.

Посмотрите на Example 4.12 from the phpunit docs


Для меня это случай, когда вы видите, что что-то не так, но проблемане в тестировании, а в коде

Вам нужно сделать что-то уродливое в своих тестах, и вы начинаете думать о покрытии кода, правилах кодирования и «обходном пути».Обычно, когда это случается со мной, я отступаю от кода и смотрю, можно ли решить проблему на другом уровне.Иногда это приводит к тому, что я обнаруживаю недостаток дизайна в своем коде.


Возвращаясь к вопросу:

Смысл в достижении 100% покрытия кода заключается в том, что у вас есть«чистый код» не означает, что вы имеете 100% покрытие кода. Весь смысл стремления к нему заключается в том, что вы действительно внимательно изучаете свой код и понимаете, почему вы не можете достичь строк своего кода при использовании класса,Это может быть проблемой дизайна.

Устранение этих недостатков приводит к легко достижимому 100% охвату.Использование хаков, чтобы просто получить «номер» правильно, обычно делает хуже, чем вообще не заботиться.Вы не только не решаете проблему, но и скрываете ее.

2 голосов
/ 04 декабря 2011

Вы можете сделать свой торт и съесть его, используя игнорировать комментарии покрытия кода , пока Xdebug не будет улучшен, чтобы обнаружить } как неисполняемый.

    // .. some data validation stuff
    trigger_error('Error validating the stuff', E_USER_WARNING);
// @codeCoverageIgnoreStart
}
// @codeCoverageIgnoreEnd

Я отправил запрос на добавление однострочного комментария, который сделал бы его более приятным для глаз.

} // @codeCoverageIgnore

Но, возможно, вам следует следовать советам стимулов и не слишком задумываться о достижении 100% покрытия.

2 голосов
/ 04 декабря 2011

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

Поскольку механизм XDebug понимает только номера строк тех строк, которые он на самом деле выполняет, я не думаю, что он может "сделать это правильно".«учитывая, что ваш стиль помещает« исходные строки »в места, которые он не может« выполнить ».

Подумайте, что произойдет, если вы напишите:

  1:   foo() {  return; 
  2:        ...1000 comment lines...
  1002:      }

То, что XDebug видит, - это выполнениевозвращение в строке 1, поэтому одна строка четко покрыта (не совсем верно, см. пример ниже);PHPUnit видит (я думаю) 1002 строки кода.Я думаю, что это даст вам 0,1% покрытия, если запустить самому(В более крупных программах такой экстремальный код маловероятен, и средние значения становятся лучше).

Таким образом, охват, который вы получаете, серьезно зависит от вашего стиля кодирования.Более неясный вариант:

  1:    bar() {   if (a) { $x=2; if (b) { $y=3 } } }

Поскольку XDebug явно отслеживает только номера строк, если вызывается bar (), строка 1 будет выполнена, и у вас будет одна строка источника, так что вы получите 100%охват.Я полагаю, что инструмент отображения графики покажет всю строку как «покрытую».Однако, если условие (a) равно false , второе условие вообще не имеет шансов быть выполненным.Вы могли бы обоснованно утверждать, что был покрыт только 50% кода (первый, если не второй).А графическое отображение неверно, поскольку $ y = 3 показано как покрытое, но это не так, поэтому вы вводите в заблуждение детали.

Чтобы получить более точное число, инструмент должен знать, чтоколичество отдельно управляемых исполняемых блоков кода (называемых "базовыми блоками" в литературе по компилятору) и количество таких блоков, которые были выполнены.В примере foo есть только один базовый блок, и если он будет выполнен, вы должны получить 100% охват всех базовых блоков, а если нет - нулевой процент, независимо от того, как вы форматируете свой код.В примере с баром есть два основных блока (запись функции и $ y = 3 внутри второго if), и вы должны получить покрытие 50%, если второй блок не выполнен, и 100%, если оно есть, независимо ото том, как он отформатирован.

Поскольку я не думаю, что PHPUnit / XDebug понимает основные блоки, я не вижу, как он может дать более точное число.(По статистике, они довольно близки; вы сказали, что ушли на 6%, и если ваша цель - набрать 80%, вам, возможно, придется набрать 74-86% в зависимости от вашего форматирования, чтобы получить 80% «распечатанного» покрытия).

Цена, которую вы платите за решение с базовыми блоками, состоит в том, что покрытие не в терминах «строк исходного кода», а скорее в терминах исполняемых блоков. Я думаю, что последний вариант является более подходящим, но ваш переход можетразличаются, и боссы обычно путаются из-за различий.

Наш инструмент PHP Test Coverage имеет это понятие базовых блоков, полученное путем точного анализа вашего исходного кода компилятором.будет производить более точные числа. Его инструмент отображения также понимает, что в строке может быть несколько операторов, и будет правильно окрашивать выполненные и невыполненные части.

...