Подтвердить что ты не робот

Как ускорить java-модульные тесты?

В настоящее время наш проект имеет более 3000 единичных тестов, а "ant testAll" занимает более 20 минут. помимо получения лучшего оборудования, есть ли способы ускорить работу?

4b9b3361

Ответ 1

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

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

Время ваших испытаний. Обычно 90% из них будут выполняться почти мгновенно, а последние 10% будут занимать почти все время. Найдите эти 10% и посмотрите, что они делают.

Запустите код через профайлер и обратите внимание, где тратится время. Угадание - пустая трата времени. То, что вы считаете испытателем-бегуном, бессмысленно. Вместо того, чтобы угадывать, узнайте, что он делает. Затем вы узнаете, как ускорить его.

Ответ 2

Некоторые идеи:

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

Ответ 3

Возможно, вы захотите разделить свои модульные тесты на апартаменты. Является ли ваше приложение модульным? Как часто вам нужно запускать все тесты? Было бы приемлемо, если бы ваши разработчики только запускали модульные тесты, относящиеся к их собственному модулю, и у вас был массив тестов, выполняемых в ночное время и/или на CI?

Существуют ли какие-либо конкретные юнит-тесты, которые очень сложны (я знаю, что я вхожу в функциональное и интеграционное тестирование здесь, но линия иногда нечеткая), но может ли любой из них работать на уровне здравомыслия во время разработки и затем выполняться полностью на CI?

Изменить: просто для пинок я кратко опишу тестовые процедуры в одном из моих предыдущих проектов.

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

  • На уровне разработчика мы использовали простой двухминутный тестовый набор под названием CheckIn, который подтвердил, что код достаточно здоров, чтобы присоединиться к багажнику.
  • Кроме того, мы непрерывно проводили тесты на работоспособность на машине CI. Это были упрощенные версии более сложных интеграционных и функциональных тестов, всех модульных тестов и всех регрессионных тестов.
  • Комплексные комплекты тестов (в количестве часов) выполнялись днем ​​и ночью удаленно, а результаты составлялись следующим утром.

Автоматическое тестирование - это мутные гайки.

Ответ 4

Начать с:
a) Получите статистику о времени выполнения ваших тестов Junit. Возможно, вы уже можете передать эту информацию в своих тестовых отчетах.
b) Выведите 10 лучших классов тестов (в сжатые сроки) и попытайтесь сократить время. Это необходимо делать на постоянной основе. c) Постарайтесь сократить время работы путем рефакторинга или даже изменения подхода к тестированию.
 Один из таких случаев, с которым я столкнулся, находится в одном тестовом классе для тестовых случаев CRUD. Тест-сценарий для Windows сначала создавал funtionlaity, а затем обновлял. Но мы уже тестировали создание в отдельном тестовом случае. Поэтому в этих случаях вы можете связать свои тестовые примеры, например

@Test()
    public void testCreate() throws Exception
    {}
    @Test(dependsOnMethods = "testCreate")
    public void testAmend() throws Exception
    {}
    @Test(dependsOnMethods = "testAmend")
    public void testDelete() throws Exception
    {} 

Таким образом, вы сохраняете повторное тестирование.

d) Еще один пример, когда я смог уменьшить время, было значительным. У нас была система (inherietd), в которой каждый тестовый пример вызывал SetUp (Strating Spring Server и т.д.) И после запуска отключенных системных ресурсов. Это было очень много времени, поэтому я реорганизовал его, чтобы запустить ресурсы coomon перед тестированием и после целого а затем закрыть их.

e) В зависимости от вашего проекта их могут быть другими узкими местами, которые вам могут потребоваться, чтобы их можно было сгладить.

Как управлять временем сборки в TDD

Ответ 5

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

Если это так, один подход заключается в многопоточности вашего тестового прогона. Test-NG поддерживает это очень хорошо. Преобразование тестов из junit в test-ng не так сложно и нужно делать только один раз.

Тесты, которые должны выполняться последовательно, могут быть легко отмечены:

@Test(sequential = true)
public class ATest {
  ...

На многоядерном компьютере вы увидите огромные улучшения во время выполнения. Даже на одном ядре вы увидите хорошее улучшение, так как некоторые потоки ожидают операции io.

Подробнее об этом можно узнать здесь:

http://beust.com/weblog/archives/000407.html

Надеюсь, что это поможет.

....

Еще несколько предложений. Я не могу поверить, что вы не используете непрерывную интеграцию. Поверьте мне, 30 разработчиков не перегружают ваш CI-сервер. Даже если вы не можете получить доступ к CI, установите hudson на свой собственный компьютер - для настройки потребуется 10 минут, а выгоды огромны. Спросите своего менеджера, что хуже, когда каждый разработчик сидит, ожидая завершения модульных тестов, или сервер сделает это за вас. Наличие тупой шляпы, которую можно носить для человека, который сломал сборку, обычно достаточно, чтобы убедить разработчиков выполнить свои модульные тесты.

Если качество проверок действительно вызывает серьезную озабоченность (не забывайте, что регистрация всегда можно отбросить назад) рассмотрите Teamcity - он запускает тесты и не передает код, если тесты не выполняются.

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

Но помните, что умные инструменты, такие как test-ng, teamcity и clover, доставят вам до сих пор - хорошие тесты не будут писать сами!

Подводя итог моему решению, попробуйте выполнить все или некоторые из следующих шагов:

  • Оптимизация тестов - издевки, общая настройка и т.д.
  • Запуск тестов в Parallel
  • Получить что-то еще для запуска тестов для вас - сделать его автономной задачей с помощью hudson или аналогичного
  • Запустите только те тесты, которые нужно запустить - сортируйте их в пакеты или используйте клевер и бамбук.

Ответ 6

Используете ли вы fork="yes" в своем вызове junit? Если это так, убедитесь, что вы установили forkMode="once", иначе задача junit запустит новую виртуальную машину для каждого класса TestCase. Благодаря 3000 единичным испытаниям это будет иметь существенное различие.

http://ant.apache.org/manual/Tasks/junit.html

Ответ 7

Очевидно, что что-то в вашем тесте занимает много времени.

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

Остальные тесты медленны либо потому, что они выполняют IO, либо потому, что они чрезмерно связаны с процессором.

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

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

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

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

Ответ 8

Хорошо, я не знаю, что делает ваш Unit-тест, но вам нужно спросить себя, почему он занимает 20 минут. По моему опыту часто бывает много тестов, которые проходят в течение нескольких миллисекунд и несколько тестов, которые составляют оставшуюся часть требуемого времени. Чаще всего это тесты с участием IO/network/DB-Stuff. Например, если вы тратите много времени на ожидание из-за задержек в сети, вы можете попробовать запустить свои тесты параллельно.

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

Ответ 9

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

  • используйте лучшее оборудование (извините)
  • упростить логику тестирования

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

Ответ 10

Я согласен с Паблоджимом. Распараллеливайте свои тесты. Мы используем clearcase и передаем все, что от наблюдателей действительно замедляет работу. Когда мы распараллеливали на дуэльре, мы получили в 6-8 раз быстрее более короткий тестовый прогон.

Мы используем фреймворк CPPUnit, и мы просто добавили скрипты python, чтобы запускать различные тестовые пакеты для разных потоков.

Мы также использовали clearmake для распараллеливания процесса сборки. Следующим шагом, вероятно, будет распараллеливание тестов на клиентах разработчиков.

Ответ 11

Перенесите полный набор тестов в систему COntinuous INtegration, поэтому разработчикам не нужно запускать их каждый раз. У таких систем больше терпения, чем у разработчиков.

Ответ 12

Я бы рассматривал это так же, как и любые другие проблемы с производительностью:

  • Не делайте предположений о том, что проблема
  • Проанализируйте выполнение теста с профилировщиком для определения горячих точек
  • Анализируйте горячие точки по одному, повторное тестирование после каждого изменения кода.

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

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

Ответ 13

Я бы предложил иметь две сборки (инкременты, которые запускаются при каждой проверке, и полная сборка, которая выполняется за ночь)

Инкрементный пробег сокращает тесты примерно за 7 минут, тогда как полная сборка запускает все тесты дольше менее чем за 40 минут.

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

Примечание. Один сервер непрерывной интеграции может иметь любое количество агентов, и если вы не можете позволить себе больше одного сервера, вы можете использовать ПК в качестве агентов сборки. (У вас должно быть не менее 30 таких)

Ответ 14

Вот такой подход, который я бы взял.

  • Просмотрите свои тестовые примеры, найдите любые избыточные тесты. С 3000 тестов, скорее всего, вы двойные и пятикратные покрытия частей, которые не должны быть.
  • Выберите "канарейки". Это те тесты, которые вы хотите всегда запускать, те, которые будут пахнуть опасностью в других частях. Скорее всего, это более сложные тестовые примеры, которые проверяют общедоступные интерфейсы API, которые используются между компонентами. Если один из этих сбоев, вы можете войти и запустить полный набор тестов для компонента.
  • Начните перенос в фреймворк, например TestNG и начните классифицировать свои тестовые примеры, а затем запустите только классифицирование того, над чем работаете с ночными полными испытаниями.

Ответ 15

Самый эффективный способ ускорить работу с большим набором тестов - это запустить его постепенно, так что только те тесты, которые касаются кода, изменились с момента последнего запуска тестового прогона. В конце концов, самыми быстрыми тестами всегда будут те, которые выполняются not. 8 ^)

Жесткая часть на самом деле заставляет это работать. В настоящее время я работаю над инкрементным тестированием для JUnit 4, который является частью инструмента "JMockit Coverage" в JMockit инструментарий для тестирования разработчика. Он все еще незрелый, но я считаю, что он будет работать хорошо.

Ответ 16

Доступ к БД и латентность сети могут быть областью для проверки. Если вы выполняете много запросов на доступ к базе данных в своих интеграционных тестах, вам может понадобиться использовать базу данных в памяти, такую ​​как HSQL, H2 или Derby, а не "настоящую" базу данных, такую ​​как Oracle. Если вы используете Hibernate, вам также придется изменить настройки в своих конфигурациях Hibernate, чтобы использовать диалект, специфичный для этой БД (например, HSQLDialect вместо OracleDialect). Был когда-то в проекте, когда каждая полная сборка должна была упасть и воссоздать всю схему Oracle и выполнить множество тестов db по сети, и иногда это занимает до 20 минут, а затем вы обнаружите, что кто-то зарегистрировался, и все было сломано еще раз.: (

В идеале вы хотели бы иметь только одну БД script, которая может использоваться для обеих баз данных, но вам может понадобиться синхронизировать два разных сценария создания БД - один для производства, один для тестов интеграции.

DB в том же JVM и DB по сети - может иметь значение.