17
  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).

  • 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. – BritishBoyinDC Jul 11 '13 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 Jul 11 '13 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 Jul 13 '13 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. – Michael Welburn Dec 26 '13 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 Jan 5 '14 at 20:06
3

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.

| improve this answer | |
  • Is UNABLE_TO_LOCK_ROW a QueryException not a DmlException? – Phil B Sep 11 '18 at 13:36
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.

| improve this answer | |
  • +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. – ca_peterson Feb 27 '14 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

| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.