5

We have a few triggers on different objects that depend on a custom setting to exist, so when we create test units on those objects, we need to create that custom setting.

We wanted to avoid having to manually create the custom setting on every test method so I thought of creating a method in a utility class to create this custom setting.

The problem is that sometimes when we run methods from the "Run All Tests" or the apex test execution (in parallel mode), we get an error on those methods "Unable to Lock Row".

The problem is that the different tests methods on different test classes try to create the same custom setting at the same time and the only way we have of preventing that is disabling parallel mode on the test execution page.

This is snippet of the method causing the issue, is there a better way to handle this?

Thank you.

public static void initCustomSettings() {

       Custom_Privleges__c custp = Custom_Privleges__c.getValues(UserInfo.getProfileId());

        if(custp==null){

        Custom_Privleges__c cp = new Custom_Privleges__c();
        cp.Override_All_Constraints__c=true;
        cp.Integration_User__c=true;
        ....
        ....        
        insert cp;  
        }    
}
  • Disable parallel execution of Test classes and it will be quick win – Mohith Shrivastava Jul 24 '13 at 11:19
  • 1
    To disable Parallel Apex Testing: Your Name > Setup > Develop > Apex Test Execution Click Options... button Check the Disable Parallel Apex Testing checkbox Click OK – Mohith Shrivastava Jul 24 '13 at 11:22
  • Thanks Mohith :), I am aware of that solution. I am just wondering if there is any better way. – PepeFloyd Jul 24 '13 at 11:28
  • I suspect not, but wanted to double check are you using SeeAllData? – Andrew Fawcett Jul 25 '13 at 11:19
  • @AndrewFawcett, we are not using or seeing the org's data. Thanks. – PepeFloyd Jul 25 '13 at 11:51
1

There is a new feature on Spring 15 which may be of assistance. Namely, there is now a way of setting up a special test class in which you can set up test data by using the @testSetup identifier. Every time your unit tests run, the data is rolled back to give you a clean slate to test from.

Example test class:

 @testSetup static void setup() {
        // Create common test accounts
        List<Account> testAccts = new List<Account>();
        for(Integer i=0;i<2;i++) {
            testAccts.add(new Account(Name = 'TestAcct'+i));
        }
        insert testAccts;        
    }
  • That will make the issue more complicated, not less, since custom settings will persist longer in isolation mode. – sfdcfox Mar 12 '15 at 16:22
  • @JackOdell - FYI - The data in TestSetup is NOT rolled back with each test method execution (at least that is not what I saw). The data persists across all tests in a class but if one test modifies the data, the modification persist throughout all the tests in the class. Only the data created during your test method is rolled back between tests in a given class – Eric Mar 12 '15 at 17:14
0

What I have and I can run parallel tests with custom settings without a problem is this: one virtual class called based test which is extended every time by a test class. That base test class has a start and a stop method and in the start method I insert whatever custom settings I have and call the official method to start a test in salesforce.

Let me know if you need for me to post some code examples, more than happy to do that.

UPDATE

This is the base test class

public virtual class BaseTest()
{
    //put your initialization here, you might want to override this in other classes if you need additional initialization 
    protected virtual void Init()
    {
       //initialize your custom setting here
    }
    public void Start()
    {
       Init();
       Test.startTest();
    }
    public void Stop();
    {
       Test.stopTest();
    }
}

And here is how you extend it in your test class

@isTest
private class TestClass extends BaseTest
{
    static testMethod void TestMethod()
    {
       t.Start();

       t.Stop();
    }

    static { BaseTest.t = new TestClass();}
    static BaseTest t { get { return BaseTest.t; }} 
}
  • Interesting, can you share some of that code? I would like to try that out. – PepeFloyd Apr 12 '15 at 22:12
  • Updated my answer. – Mihai Neagoe Apr 12 '15 at 22:41

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.