3

I have a few test classes that fail but only when all the test classes are run in parallel.I'm using a hierarchy custom setting as part of the test code. In order to narrow down the problem I have the following in my test code:

My_Setting__c settings = My_Setting__c.getOrgDefaults();
settings.some_app_date__c = System.today()+1;
upsert settings;

Ctl_SomePage ctrl = new Ctl_SomePage();
My_Setting__c settings1 = My_setting__c.getOrgDefaults();
system.assert(false,'date: ' + settings1.some_app_date__c);

When run by itself or with parallel disabled this produces a date:

System.AssertException: Assertion Failed: date: 2016-03-01 00:00:00

When run with all tests and parallel enabled I get:

System.DmlException: Upsert failed. First exception on row 0; first error: DUPLICATE_VALUE, duplicate value found: SetupOwnerId duplicates value on record with id: 00DP0000003oTNU: []

If I try to just log out the custom setting its just an empty object. It seems like it won't let me update it but if I try to get the values from it, its empty...

Any suggestions?

  • Disable parallel testing? – Adrian Larson Feb 29 '16 at 20:54
  • @AdrianLarson haha yes, that is an option but I like being able to run them in parallel and I'm also curious to find out what's going on. If there is no workaround however, I'll do so. – Phil B Feb 29 '16 at 20:56
  • 2
    I met that before. Idea would be to simulate custom settings into specific wrappers, that would return some value for tests only. Or use upsert, which is more dangerous as well as it can cause test failures. – kurunve Feb 29 '16 at 21:01
0

Just an example of how mocking could work (based on @kurunve's comment):

public class MySettingMock
{
    @TestVisible static Date mockSettingDate;
    public static Date getOrgWideDefaultDate()
    {
        return Test.isRunningTest() ? mockSettingDate :
            My_Setting__c.getOrgDefaults().Date_To_Mock__c;
    }
    public static void setOrgWideDefaultDate(Date value)
    {
        My_Setting__c defaults = My_Setting__c.getOrgDefaults();
        defaults.Date_To_Mock__c = value;
        if (Test.isRunningTest()) { mockSettingDate = value; }
        else { upsert mockSettingDate; }
    }
}

The way the above is structured, the only line you can't hit from a test is the upsert operation. I haven't tried it myself, but it's an interesting idea. It doesn't scale especially well if you have a bunch of values to work with, but there could be workarounds for that.

  • 1
    @PhilB Adrian has a good idea here; an even more general approach would be to use a class to fetch all custom settings and the class gets the actual settings from a concrete interface implementation (Prod impl uses actual getInstance(), getOrgDefaults().. methods whereas test concrete impl of interface returns sobjects. Testmethod overrides class interface variable impl to use before starting test; overrides required only where needed. This is an alternative to mocking via DML custom settings. Avoids putting Test.isRunningTest() into Prod code at the cost of more 'infrastructure' – cropredy Mar 1 '16 at 5:12

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.