18
  1. All of my classes, triggers, pages, components are set to API Version 28.0, Summer '13.
  2. None of my test classes/methods use SeeAllData=true annotation.
  3. Most of my test classes/methods insert identical test data into a list Custom Setting, as every test starts with a blank slate, and this Custom Setting config is required for testing most parts of my application.

Prior to Summer '13 (28.0), in Spring '13 (27.0) and earlier, my test code, which didn't change, ran just fine in parallel, I never saw the UNABLE_TO_LOCK_ROW Custom Setting contention until Summer '13 (28.0).

9
  • 4
    I've seen this as well- the only way I was able to get round it was to go to Apex Test Execution and under options, check the Disable Parallel Apex Testing. I believe all deployments to Production run in this serial mode. Commented Jul 11, 2013 at 19:55
  • Correct @BritishBoyinDC that works around the issue, and you're correct about deployments to production running in serial as well, so this is not a blocking issue. But, it certainly makes the develop/test cycle much slower when you have a lot of unit tests, as running in parallel is like 10 times faster, so I'd really love to find a fix.
    – mjgallag
    Commented Jul 11, 2013 at 20:07
  • 1
    The UNABLE_TO_LOCK_ROW error started for me back in V26.0; disabling parallel test execution is the only solution I know of. I tend to get the locking on creating Users or Custom Settings
    – cropredy
    Commented Jul 13, 2013 at 1:13
  • Have you filed a case with Salesforce about this? I think @BritishBoyinDC hit the nail on the head with his comment (I've run into the same issue and used the same solution) but we are probably at Salesforce's mercy on a true fix. Commented Dec 26, 2013 at 15:10
  • 1
    @TimSmith Full disclosure, I'm not currently working in the org I faced this issue in 5 months ago. That being said, your suggested workaround sounds plausible to me, although not preferable to a bug fix from SFDC :)
    – mjgallag
    Commented Jan 5, 2014 at 20:06

3 Answers 3

4

I had to combat this in our environment when trying to move towards running tests in parallel. I ended up using a centralized static method (e.g. in a test utility class) to configure a given custom setting.

The first thing the method does is check the database for an existing custom setting record filtered by the id of the current user's context. If I find one then I can proceed to update it if needed, otherwise, I build a new custom setting object and set it up the way I want. The most important thing to note here is the Name field acts as the external id for the table. Make sure you set up each custom setting with a unique name. Finally, upsert the object and use the Name field as the external id.

I can go into some of the theory behind why I think I had to use this method if you want, but I'll spare you. Hah.

Here's some code:

public static void setupMyCustomSetting(Boolean value, String name) {
    try {
        My_Custom_Setting__c customSetting = [
            SELECT
                My_Custom_Field__c
            FROM My_Custom_Setting__c
            WHERE SetupOwnerId = :UserInfo.getUserId()
        ];

        customSetting.My_Custom_Field__c = value;
        update customSetting;
    } catch (QueryException ex) {
        My_Custom_Setting__c customSetting = new My_Custom_Setting__c(
            Name = name,
            SetupOwnerId = UserInfo.getUserId(),
            My_Custom_Field__c = value
        );

        Database.upsert(customSetting, My_Custom_Setting__c.Name.getDescribe().getSObjectField(), false);
    }
}

Put this in a test utility class and call it from each test class's testSetup method (or static block if you're still using that paradigm). I just pass in the name of the test class into the above method.

Something like:

MyTestUtilityClass.setupMyCustomSetting(false, 'MyTestClass');

Then when you're writing your unit tests, you can flip the status of your custom setting by calling the same facility. Obviously this is a rudimentary example, but you can get fancy and pass in a more complicated data structure if you wanted.

Let me know if this works out for anyone.

2
  • Is UNABLE_TO_LOCK_ROW a QueryException not a DmlException?
    – Phil B
    Commented Sep 11, 2018 at 13:36
  • 6 years late to asking this - BUT - when you say "Make sure you set up each custom setting with a unique name"... if two different tests need to create the same custom setting, is it better to use the SAME value for Name field between them, or DIFFERENT per unit test?
    – Charles T
    Commented Oct 22, 2021 at 15:55
1

Since nobody seems to have posted a response as an answer, to remove this from the unanswered questions queue, I'll just post what @BritishBoyInDC said:

I've seen this as well- the only way I was able to get round it was to go to Apex Test Execution and under options, check the Disable Parallel Apex Testing. I believe all deployments to Production run in this serial mode.

1
  • +1 about metadata API-invoked test runs being serial. That encompasses deployments and is really the "cannonical" way that test runs are counted for anything that matters. Commented Feb 27, 2014 at 6:38
1

This is from documentation . Probable cause -

  • When tests update the same records at the same time. Updating the same records typically occurs when tests don’t create their own data and turn off data isolation to access the organization’s data.
  • When a deadlock occurs in tests that are running in parallel and that try to create records with duplicate index field values. Test data is rolled back when a test method finishes execution. A deadlock occurs when two running tests are waiting for each other to roll back data, which happens if two tests insert records with the same unique index field values in different orders.

Try running it with "Disbale Parallel Running" in Options as true. It will work

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .