3

I currently use a genuinely wonderful add-on component FieldsetLightningCompForm to display input/output fields on records that reference Field Sets to determine what is shown. It's beyond useful for Lightning. However, I have come across an issue recently that the test for it fails everytime I try to deploy it due to timing out. While I can circumvent this in some cases, I can't in every case (we have some packages that auto-generate code).

Can anyone help with writing a test case that won't time out every time its run? The code for everything is below. Worth noting, the test case method is even labeled as "neverWriteTestMethodLikeThis()", which doesn't bode well...

public class FieldSetController {

    @AuraEnabled
    public static List<String> getTypeNames() {
        Map<String, Schema.SObjectType> types = Schema.getGlobalDescribe();
        List<String> typeNames = new List<String>();
        String typeName = null;
        List<String> fsNames;
        for (String name : types.keySet()) {
            if (hasFieldSets(name)) {
                typeNames.add(name);        
            }
        }
        return typeNames;
    }

    @AuraEnabled
    public static Boolean hasFieldSets(String typeName) {
        Schema.SObjectType targetType = Schema.getGlobalDescribe().get(typeName);
        Schema.DescribeSObjectResult describe = targetType.getDescribe();
        Map<String, Schema.FieldSet> fsMap = describe.fieldSets.getMap();
        return !fsMap.isEmpty();
    }

    @AuraEnabled
    public static List<String> getFieldSetNames(String typeName) {
        Schema.SObjectType targetType = Schema.getGlobalDescribe().get(typeName);
        Schema.DescribeSObjectResult describe = targetType.getDescribe();
        Map<String, Schema.FieldSet> fsMap = describe.fieldSets.getMap();
        List<String> fsNames = new List<String>();
        for (String name : fsMap.keySet()) {
            fsNames.add(name);
        }
        return fsNames;
    }

    @AuraEnabled
    public static List<FieldSetMember> getFields(String typeName, String fsName) {
        Schema.SObjectType targetType = Schema.getGlobalDescribe().get(typeName);
        Schema.DescribeSObjectResult describe = targetType.getDescribe();
        Map<String, Schema.FieldSet> fsMap = describe.fieldSets.getMap();
        Schema.FieldSet fs = fsMap.get(fsName);
        List<Schema.FieldSetMember> fieldSet = fs.getFields();
        List<FieldSetMember> fset = new List<FieldSetMember>();
        for (Schema.FieldSetMember f: fieldSet) {
            fset.add(new FieldSetMember(f));
        }
        return fset;
    }
}
public class FieldSetMember {

    public FieldSetMember(Schema.FieldSetMember f) {
        this.DBRequired = f.DBRequired;
        this.fieldPath = f.fieldPath;
        this.label = f.label;
        this.required = f.required;
        this.type = '' + f.getType();
    }

    public FieldSetMember(Boolean DBRequired) {
        this.DBRequired = DBRequired;
    }

    @AuraEnabled
    public Boolean DBRequired { get;set; }

    @AuraEnabled
    public String fieldPath { get;set; }

    @AuraEnabled
    public String label { get;set; }

    @AuraEnabled
    public Boolean required { get;set; }

    @AuraEnabled
    public String type { get; set; }
}

Test Class

@isTest
public class FieldSetControllerTest {
    public static String typeName = 'Contact';
    public static String fsName = 'lightningFormContactFields';
    @isTest
    public static void neverWriteTestMethodLikeThis(){
        FieldSetController.getFields(typeName, fsName);
        FieldSetController.getFieldSetNames(typeName);
        FieldSetController.getTypeNames();
        FieldSetController.hasFieldSets(typeName);
    }
}

Looking for anything that can help. Thanks!

2
  • I've an answer, but I'm mobile. I'll write it up when I get home.
    – sfdcfox
    Commented Jan 8, 2020 at 0:23
  • 2
    Is there any reason you can't breakout all the four method calls in neverWriteTestMethodLikeThis() into separate test methods? There doesn't appear to be any direct dependency from one call to the next. While you were at it, try and make some useful assertions based on the expected outcomes. Commented Jan 8, 2020 at 0:41

1 Answer 1

2

I suspect part of the problem is the repeated calls to Schema.getGlobalDescribe().

That method returns metadata for all the accessible sObjects and is generally expensive if you are only interested in one particular sObject.

So, instead of doing this:

Schema.SObjectType targetType = Schema.getGlobalDescribe().get(typeName);
Schema.DescribeSObjectResult describe = targetType.getDescribe();

Try something simpler like:

Schema.DescribeSObjectResult describe = Schema.describeSObjects(new String[]{typeName})[0];

If you want to take it a step further, have a read of Why is Schema.describeSObjects(types) Slower Than Schema.getGlobalDescribe()?. As sfdcfox suggested, you will get even better results using Type.forName. E.g.

Schema.DescribeSObjectResult describe = ((SObject)(Type.forName('Schema.'+typeName).newInstance())).getSObjectType().getDescribe();

Also, break your test methods into four distinct tests. One for each method. E.g.

@isTest
public class FieldSetControllerTest {
    public static String typeName = 'Contact';
    public static String fsName = 'lightningFormContactFields';

    @isTest
    public static void contactsHaveAFieldSetDefined(){
        boolean contactsHaveAFieldSet = FieldSetController.hasFieldSets(typeName);
        System.assert(contactsHaveAFieldSet);
    }

    // Plus more tests. Each focusing on one method at a time and making assertions.
}
2
  • 3
    I have a better solution using Type.forName, but this is still much better than repeated global describes.
    – sfdcfox
    Commented Jan 8, 2020 at 1:23
  • 1
    I made the changes you suggested, Daniel, and they appear to have cleared up the issue. Thanks!
    – Evan Kelly
    Commented Jan 8, 2020 at 21:14

You must log in to answer this question.

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