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

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

Может кто-нибудь объяснить, какие данные/контекст распределяются между отдельными тестами при параллельном выполнении?

6
Swisher Sweet 27 Май 2021 в 18:35

3 ответа

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

По моему опыту, это происходит почти полностью вокруг пользовательских настроек.

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

Могут быть и другие случаи утечки, которые, я уверен, будут добавлены в качестве дополнительных ответов.

7
Phil W 27 Май 2021 в 19:04
1
Это пример из учебника, с которым сталкивалось большинство из нас.
 – 
Adrian Larson
27 Май 2021 в 19:11

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

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

Другой случай, который мы видели, — это тесты, которые создавали записи контактов, но по умолчанию использовали эти записи для учетной записи по умолчанию. Блокировка записей происходит в корневом объекте дерева мастер-подробности, поэтому, когда тесты, работающие параллельно, манипулируют несколькими Контактами, но только с одним Пользователем, к которому применялась блокировка, у нас возникла проблема с ошибкой блокировки. Эти тесты теперь были изменены, чтобы создать независимую учетную запись для каждого контакта.

6
Keith C 27 Май 2021 в 18:57

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

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

Два решения: либо (а) создавать случайные уникальные значения в ваших модульных тестах, либо (б) использовать isParallel=false для отключения параллельного тестирования проблемных тестов (вы можете выбрать параллельный запуск некоторых тестов для эффективности и изолировать проблемные тесты). в последовательном режиме).

3
sfdcfox 27 Май 2021 в 20:18
1
Я думал, что @paralel=false не работает, или я что-то пропустил? trailblazer.salesforce.com/ideaView?id=0873A0000003VhKQAU
 – 
Kasper
28 Май 2021 в 04:54