2

How can the Test Coverage can be fulfilled for the Apex classes which queried for External Objects.I have written Test class just like assuming External Object behaves like a custom Object but getting error repetitively "CANNOT_INSERT_UPDATE_ACTIVATE_ENTITY: You can't create records for the object".

I used the DML statements like Database.insertAsync but no use. Gone through some articles saying that we need to mock the external object for the Apex Test coverage on External Object. If so is there document which explains about this concept.

3
  • Did you try a go at this answer? - salesforce.stackexchange.com/questions/130991/… Nov 4, 2019 at 21:19
  • I have gone through it but i feel it's not covering the 360 degree view. Is there any document provided by Salesforce with regard to this.
    – Venkat V
    Nov 4, 2019 at 21:24
  • Vote for the Idea here. I've seen that the Salesforce Connect product team has a native mocking framework on their roadmap. Nov 6, 2020 at 7:16

1 Answer 1

7

Typically we just set up a simple mock for this type of testing. You can have a class which just passes records through normally, but then when you overwrite it passes whatever you choose:

public virtual inherited sharing class Query
{
    public static List<SObject> records(List<SObject> records)
    {
        return instance.passThrough(records);
    }

    static Query instance = new Query();
    @TestVisible static void setMock(Query mock) { instance = mock; }

    protected virtual List<SObject> passThrough(List<SObject> records)
    {
        return records;
    }
}

Once you've got this mocking set up, wrap your query in this method in your service:

public with sharing class MyService
{
    public static void doStuff()
    {
        for (My_External_Object__x record : Query.records([
            SELECT ... FROM My_External_Object__x
        ])){
            // logic
        }
    }
}

In your test, usage would then look like:

@IsTest
class MyTests
{
    class Mock extends Query
    {
        final List<My_External_Object__x> externalRecords;
        Mock(List<My_External_Object__x> externalRecords)
        {
            this.externalRecords = externalRecords;
        }

        protected override List<SObject> passThrough(List<SObject> records)
        {
            return externalRecords;
        }
    }

    @IsTest staticVoid testStuff()
    {
        List<My_External_Object__x> mockRecords = new List<My_External_Object__x>();
        // populate as desired

        Query.setMock(new Mock(mockRecords));

        Test.startTest();
            MyService.doStuff();
        Test.stopTest();

        // make assertions
    }
}
5
  • I came across this when running into the same issue of finding a solution for testing external objects. I was able to implement this pretty well but I am curious how to handle it when my class talks to several external objects. How would the test be structured to handle multiple? Mostly confused with the class Mock extends Query section and how this would look with multiple external objects.
    – SBB
    Jan 30, 2020 at 22:07
  • @SBB When we had to support multiple objects, we built out a generic mock which would cache a Map<SObjectType, List<SObject>>.
    – Adrian Larson
    Jan 31, 2020 at 0:28
  • Thanks, I will see what I can come up with. Any of that out on a public git repo by chance? Sorry to hi-jack the question, very little info out there on unit testing external objects!
    – SBB
    Jan 31, 2020 at 1:00
  • @SBB No problem at all. I just worry posting our solution to that part of the problem might get us in hot water with legal.Trying to keep the discussion in general terms.
    – Adrian Larson
    Jan 31, 2020 at 14:49
  • If your able to answer a question directly without linking to other company resources, I have a bounty open for essentially the same question - salesforce.stackexchange.com/questions/293015/…
    – SBB
    Feb 3, 2020 at 17:05

You must log in to answer this question.

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