Комментарии 27
Ради таких твитов стоит жить и работать, да.
Классно. Я писал патч для issue10, отправил его на review, но ответа так и не получил. У вас проблем с выборочным запуском тестов нет? Не работаете над этим issue?
Как вам код phpunit? На мой взгляд очень тяжелый для понимания-рефакторинга
Как вам код phpunit? На мой взгляд очень тяжелый для понимания-рефакторинга
Спасибо за вопросы!
Нет, над issue10 мы не работали. Проблем с выборочным запуском тестов так же не имели. --filter вполне себе справляется с нашими задачами.
По поводу понятности кода phpunit — тоже особых проблем не испытывали. Код замечательно читается и дорабатывается + хорошая документация. С чем именно у вас были проблемы? Уверен что сообщество поможет ответить на ваши вопросы.
Нет, над issue10 мы не работали. Проблем с выборочным запуском тестов так же не имели. --filter вполне себе справляется с нашими задачами.
По поводу понятности кода phpunit — тоже особых проблем не испытывали. Код замечательно читается и дорабатывается + хорошая документация. С чем именно у вас были проблемы? Уверен что сообщество поможет ответить на ваши вопросы.
Да, "--filter вполне себе справляется с нашими задачами", но суть в том что он при этом начинает дергать классы, методы, dataProvider'ы, которые точно под этот filter не попадают. Вот примерный тест, не знаю насколько он сейчас актуален: github.com/ewgRa/phpunit/commit/5b12236856d3c139b37ebf9a55d76733e8c08554
В итоге допустим в Zend Framework (или Symphony, не помню точно) запускать тесты с --filter то еще удовольствие. Они в dataProvider запихивают достаточно емкую работу и все эти dataProvider будут выполнятся, даже если методы, которые фильтруются не учавствуют в тестах.
> С чем именно у вас были проблемы?
Я уже точно не помню, но там мне показалась архитектура, которая явно строится по принципу дерева от крупного к мелкому или тому подобное реализована очень, очень сложно. В итоге как-то это рефакторить было очень проблематично. Мне кажется то, что это issue уже три года как не закрывается именно из-за архитектуры и того кода, кторый там реализован, уж слишком сложно он поддается рефакторингу.
В итоге допустим в Zend Framework (или Symphony, не помню точно) запускать тесты с --filter то еще удовольствие. Они в dataProvider запихивают достаточно емкую работу и все эти dataProvider будут выполнятся, даже если методы, которые фильтруются не учавствуют в тестах.
> С чем именно у вас были проблемы?
Я уже точно не помню, но там мне показалась архитектура, которая явно строится по принципу дерева от крупного к мелкому или тому подобное реализована очень, очень сложно. В итоге как-то это рефакторить было очень проблематично. Мне кажется то, что это issue уже три года как не закрывается именно из-за архитектуры и того кода, кторый там реализован, уж слишком сложно он поддается рефакторингу.
Я понимаю о чем вы говорите. Действительно, с этой точки зрения архитектура выглядит не очень оптимальной.
Мы, чтобы не натыкаться на подобные подводные камни, используем простое правило в нашем проекте — «data provider'ы должны возвращать только статичные данные». Никаких объектов, никакой хитрой логики. Если нужны различные объекты в тестах, то в датапровайдерах надо возвращать правила или параметры для создания таких объектов. А сами объекты надо создавать уже в тестах или setUp'е и очищать в tearDown'е.
Это, конечно, не исключает сбор провайдеров при запуске тестов с фильтром, но существенно облегчает этот процесс.
Более того, то, что провайдеры инициализируются задолго до выполнения тестов ведет к еще одной проблеме — нарушению изоляции. Объект, созданный перед всем набором тестов может быть изменен каким-нибудь тестом до нужного и в нужный тест объект может прийти измененным.
Это еще одна причина, почему мы запрещаем инициализацию объектов в провайдерах.
То же самое справедливо и для некоторых других методов фреймворка, вы совершенно правы.
Для автоматического контроля ситуации мы даже добавили в нашу запускалку тестов специальный тест, который проверяет состояние объектов между тестами — «SanityCheck». Правило + автоматическая проверка спасают :-).
Мы, чтобы не натыкаться на подобные подводные камни, используем простое правило в нашем проекте — «data provider'ы должны возвращать только статичные данные». Никаких объектов, никакой хитрой логики. Если нужны различные объекты в тестах, то в датапровайдерах надо возвращать правила или параметры для создания таких объектов. А сами объекты надо создавать уже в тестах или setUp'е и очищать в tearDown'е.
Это, конечно, не исключает сбор провайдеров при запуске тестов с фильтром, но существенно облегчает этот процесс.
Более того, то, что провайдеры инициализируются задолго до выполнения тестов ведет к еще одной проблеме — нарушению изоляции. Объект, созданный перед всем набором тестов может быть изменен каким-нибудь тестом до нужного и в нужный тест объект может прийти измененным.
Это еще одна причина, почему мы запрещаем инициализацию объектов в провайдерах.
То же самое справедливо и для некоторых других методов фреймворка, вы совершенно правы.
Для автоматического контроля ситуации мы даже добавили в нашу запускалку тестов специальный тест, который проверяет состояние объектов между тестами — «SanityCheck». Правило + автоматическая проверка спасают :-).
При вашем количестве тестов, даже такие «пустые» dataProvider'ы должны неплохо замедлять выполнение тестов с --filter + расход памяти (если я правильно помню там все эти результаты dataProvider складываются в память)
С одной стороны я рад за вас, с другой жаль :) Может если бы для вас это было проблемой, ваших ресурсов хватило бы, чтобы сдвинуть это дело с мертвой точки.
С одной стороны я рад за вас, с другой жаль :) Может если бы для вас это было проблемой, ваших ресурсов хватило бы, чтобы сдвинуть это дело с мертвой точки.
А можно ли вообще отказаться от data provider'ов? Мне кажется они не добавляют читаемости в тест, а скорее наоборот.
Кстати, можете дать ссылку на пример «тяжелых датапровайдеры» в зенде или в симфони.
Кстати, можете дать ссылку на пример «тяжелых датапровайдеры» в зенде или в симфони.
Провайдеры очень удобная штука. При правильно написанном тесте очень легко в случае наличия провайдеров добавлять дополнительные проверки.
На «тяжелые» провайдеры зенда и симфони тоже бы с удовольствием посмотрел. При беглом осмотре кода симфони я увидел только статичные данные в провайдерах. Может переписали уже?
На «тяжелые» провайдеры зенда и симфони тоже бы с удовольствием посмотрел. При беглом осмотре кода симфони я увидел только статичные данные в провайдерах. Может переписали уже?
К сожалению не могу, ZF2 требует phpunit 3.7, запустить тесты посмотреть не могу. Дело давно было, с тех пор я не касался этого вопроса.
Добавляя дополнительные наборы данных можно увеличить покрытие кода без написания нового теста.
>>> но суть в том что он при этом начинает дергать классы, методы, dataProvider'ы, которые точно под этот filter не попадают
Для PHPStorm я сделал External Tool в настройках, который по хоткею запускает тесты в dev-системе (линукс через plink.exe), фильтруя по выделенному мышкой методу или классу. Самая длинная строка настройки (не считая пути к плинку):
--filter='/::FULL_CLASS_OR_METHOD_NAME( .*)?$/' /path/to/TestFile.php
Для PHPStorm я сделал External Tool в настройках, который по хоткею запускает тесты в dev-системе (линукс через plink.exe), фильтруя по выделенному мышкой методу или классу. Самая длинная строка настройки (не считая пути к плинку):
-load PUTTY_PROFILE_NAME -pw PASSWORD phpunit --verbose --bootstrap=/path/to/Bootstrap.php --filter='/::$SelectedText$( .*)?$/' /path/to/document/root/$/FileRelativePath$
В
PHPUnit
из коробки есть 4 возможности выборочного запуска тестов, подробнее в другом комментарии.Вы не перестаете радовать отличными постами по QA, это «свежие глотки воздуха» в пустоте этой тематике хабра. Прочитал с удовольствием. Задумываетесь ли Вы об особенностях этого линейного механизма подсчета покрытия. По факту это все крутится около «вызвалась строка — не вызвалась». Тематика ухода к более интеллектуальному подсчету CC очень интересна.
PS Улучшать что-то в общее благо это неоспоримо ЗДОРОВО!
PS Улучшать что-то в общее благо это неоспоримо ЗДОРОВО!
Спасибо!
Да, вы правы — простой подсчет покрытия по строкам, которые были вызваны, это не панацея. Даже при огромном покрытии кода тестами нельзя считать что все хорошо и быть на 100% уверенным в том что все работает.
Для нас это просто еще одна метрика, которая позволяет понять состояние кода на разных этапах тестирования. Еще один семафор, говорящий о том, как все участники процесса разработки относятся к качеству производимого продукта.
О более интеллектуальном подсчете покрытия пока не задумывались, но вполне возможно что к этому придем.
Да, вы правы — простой подсчет покрытия по строкам, которые были вызваны, это не панацея. Даже при огромном покрытии кода тестами нельзя считать что все хорошо и быть на 100% уверенным в том что все работает.
Для нас это просто еще одна метрика, которая позволяет понять состояние кода на разных этапах тестирования. Еще один семафор, говорящий о том, как все участники процесса разработки относятся к качеству производимого продукта.
О более интеллектуальном подсчете покрытия пока не задумывались, но вполне возможно что к этому придем.
Мутационное тестирование не пробовали внедрить?
Более интеллектуальное покрытие можно реализовать на основе стандартных возможностей PHPUnit — Appendix B. Annotations — @covers. Позволяет указать что именно стоит учитывать как вызванные строки для каждого конкретного теста, весь остальной код в рамках теста будет считаться не исполненным.
Спасибо, как раз сегодня мы начали прикручивать code coverge и phpconv к нашим распределенным тестам, а тут такой open source подарок :)
Может подскажете, нет ли какой нибудь хитрости чтобы code coverage собирался быстрее? Или же проще дать CI серверу процессор побыстрее?
Может подскажете, нет ли какой нибудь хитрости чтобы code coverage собирался быстрее? Или же проще дать CI серверу процессор побыстрее?
Быстрее — только многопоточный запуск может помочь. К сожалению с xdebug'ом, собирающим покрытие, тесты идут медленнее, это факт.
Тесты для сбора покрытия мы гоняем на виртуалке с 32 гигабайтами оперативной памяти и 24ю ядрами Intel Xeon 2.93GHz. При этом из упомянутых 2,5 часов процентов 70 времени уходит именно на прогон всех тестов.
Вероятно, скоро мы придем к вопросу оптимизации еще раз, так как количество тестов с каждым днем увеличивается. Если придумаем что-нибудь, обязательно напишем об этом и отдадим в opensource.
Тесты для сбора покрытия мы гоняем на виртуалке с 32 гигабайтами оперативной памяти и 24ю ядрами Intel Xeon 2.93GHz. При этом из упомянутых 2,5 часов процентов 70 времени уходит именно на прогон всех тестов.
Вероятно, скоро мы придем к вопросу оптимизации еще раз, так как количество тестов с каждым днем увеличивается. Если придумаем что-нибудь, обязательно напишем об этом и отдадим в opensource.
Спасибо за ответ. Мы думаем в свободное время попробовать разобраться с Gearman'ом, ведь в наличии есть около сотни девелоперских и обычных офисных компов, если бы удалось запускать паралельно тесты на них, все бы просто летало! :) А вы не пробовали что-то похожее?
Пока не пробовали, но идеи такие давно витают. Де-факто тесты (не для кавериджа, а для задач, билдов и т.д.) мы итак гоняем в облаке. Набор из десятка виртуалок, из которых берется самая свободная и запускаются на ней тесты.
В общем-то такой же принцип можно применить и к девелоперским машинам, но тут возникают проблемы с окружением. Если виртуалки еще более-менее можно продублировать с точки зрения продакшеновских машин — ресурсы, версии софта и библиотек, то с клиентскими машинами такое будет очень сложно провернуть.
В общем-то такой же принцип можно применить и к девелоперским машинам, но тут возникают проблемы с окружением. Если виртуалки еще более-менее можно продублировать с точки зрения продакшеновских машин — ресурсы, версии софта и библиотек, то с клиентскими машинами такое будет очень сложно провернуть.
Success Story
При помощи --group или --fiter разделите существующий набор на части.
P. S.
Разбить потоки на почти равные части чтобы все они выполнялись примерно одинаковое время можно при помощи Chapter 7. Organizing Tests — Composing a Test Suite Using XML Configuration или же можно не заморачиваться и просто раскидать все по директориям — Chapter 7. Organizing Tests — Composing a Test Suite Using the Filesystem.
P. P. S.
Есть идея расширить возможности PHPUnit и реализовать возможность запуска набора тестов на указанном кол-ве потоков с автоматическим распределением тестов по «свободным» потокам, но это уже совсем другая история.
При помощи --group или --fiter разделите существующий набор на части.
--group
потребует измений в файлах с тестами, --filter
— подобрать правильные маски чтобы ничего не потерялось. Когда разделив запуск на несколько потоков вы добьетесь его выполнения (при определенном объеме тестов вы столкнетесь с проблемами не изолированности тестов друг от друга, зависимости от внешних ресурсов и т. п.) вы сможете ускорить процесс в десятки раз, все в конечном итоге упрется в коль-во процессов на которые хватит ресурсов (в основном памяти и процессора, но так же могут быть проблемы со скоростью записи на диск, это зависит от характера тестов) при параллельном запуске. Дальше запускаем сколько нам нужно потоков с помощью простого bash скрипта:#!/bin/bash -x
# Получаем данные покрытия для первой половины тестов выполняя в фоне
phpunit --group A --coverage-php coverage/data/group_A.cov &
# Получаем данные покрытия для второй половины тестов выполняя в фоне
phpunit --group B --coverage-php coverage/data/group_B.cov &
# Ждем пока завершатся оба потока выполняясь параллельно
wait
# Объединяем даныне покрытия из двух потоков и генерируем HTML
phpcov --merge --html coverage/html coverage/data
P. S.
Разбить потоки на почти равные части чтобы все они выполнялись примерно одинаковое время можно при помощи Chapter 7. Organizing Tests — Composing a Test Suite Using XML Configuration или же можно не заморачиваться и просто раскидать все по директориям — Chapter 7. Organizing Tests — Composing a Test Suite Using the Filesystem.
P. P. S.
Есть идея расширить возможности PHPUnit и реализовать возможность запуска набора тестов на указанном кол-ве потоков с автоматическим распределением тестов по «свободным» потокам, но это уже совсем другая история.
Проекты с автоматическим распределенным Phpunit уже есть на gihub'е. Проблемы начинаются с появлением интеграционных и функциональных тестов. Например использование БД или файлов. Можно передавать в потоки Phpunit параметры, и с их помощью создавать уникальные БД, файлы, и т. д. но в проектах с фреймворками (SF2, Doctrine) очень трудно все предусмотреть и изменить. Проще(?) всего запускать тесты в параллель на различных виртуалках.
В PHPUnit есть известный bug с покрытием таких конструкций:
If в данном случае не отработает, однако Xdebug считает его покрытым. Как выход можно заключить операторы после if в фигурные скобки:
Тогда Xdebug будет нормально считать покрытие, но только для первой конструкции. Вторую он все так же будет считать покрытой.
Вопрос вот в чем, как в badoo справляетесь с этой проблемой?
$var = false;
if($var == true)
return false;
if($var == true) return false;
If в данном случае не отработает, однако Xdebug считает его покрытым. Как выход можно заключить операторы после if в фигурные скобки:
$var = false;
if($var == true) {
return false;
}
if($var == true) { return false; }
Тогда Xdebug будет нормально считать покрытие, но только для первой конструкции. Вторую он все так же будет считать покрытой.
Вопрос вот в чем, как в badoo справляетесь с этой проблемой?
Зарегистрируйтесь на Хабре, чтобы оставить комментарий
Code coverage в Badoo