---
schema_version: "1"
id: ee95e9ab840be5a2abe865eab5754921f7ef5c8c11304b82ec09752a59fbac1d
title: Mock SOQL Tests for External Objects
collection: legacydeveloper
version: current
locale: en-us
portal_url: https://docs.salesforce.com/legacydeveloper/current/en-us/apexcode/apex_connector_external_objects_mock_soql_tests.md
canonical_url: https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_connector_external_objects_mock_soql_tests.htm
source_site: developer.salesforce.com
content_type: documentation
content_hash: a550f044ea8bd851bc89ff78498391443c2a0584c0558000123d521d850c9deb
description: You can mock SOQL query responses for external objects in Apex testing by using SOQL stub methods and a new test class. Use basic and joined SOQL queries against external objects and return mock records in a testing context.
---
# Mock SOQL Tests for External Objects

You can mock SOQL query responses for external objects in Apex testing by using SOQL stub methods and a new test class. Use basic and joined SOQL queries against external objects and return mock records in a testing context.

Create mock test classes by extending the new System.SoqlStubProvider class and overriding the handleSoqlQuery() class method. Create external object records using either Test.createStubQueryRow() or Test.createStubQueryRows(). Register the mock provider in the test using Test.createSoqlStub() and execute the test code.

![Note](https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/images/icon_note.png)

#### Note

Apex governor limits apply to the stubbed records.

The SOQL query must be against an external object, either directly with a FROM clause or via a subquery. These features aren’t allowed within a stub implementation.

- SOQL
- SOSL
- Callouts
- Future methods
- Queueable Jobs
- Batch Jobs
- DML
- Platform events

This example shows a mock test class for a class called GithubIssueTest with joined and basic queries.

/\*\*
 \*   Test class that utilizes the SoqlStubProvider classes.
 \*   Each test sets the appropriate SoqlStubProvider
 \*   and runs validation against the mocked query results.
 \*\*/

@IsTest
public with sharing class GithubIssueTest {
    @IsTest
    static void testGithubIssueQuery() {
        QueryIssueUtil queryIssueUtil = new QueryIssueUtil();
        SObjectType type = queryIssueUtil.getSObjectTypeForDynamicSoql('GithubIssues\_\_x');
        Test.createSoqlStub(type, new IssueStubProvider());
        Test.startTest();
        Assert.isTrue(Test.isSoqlStubDefined(type));
        Assert.isTrue(queryIssueUtil.queryGithubIssuesAndCheckForId());
        Assert.areEqual(1, Limits.getQueries());
        Assert.areEqual(1, Limits.getQueryRows());
        Assert.areEqual(0, Limits.getAggregateQueries());
        Assert.isTrue(queryIssueUtil.queryGithubIssuesAndVerifyResultSize(1));
        Assert.areEqual(2, Limits.getQueries());
        Assert.areEqual(2, Limits.getQueryRows());
        Assert.areEqual(0, Limits.getAggregateQueries());
        Test.stopTest();
    }

    @IsTest
    static void testIssueToCommentJoinQuery() {
        QueryIssueUtil queryIssueUtil = new QueryIssueUtil();
        Test.createSoqlStub(GithubIssues\_\_x.SObjectType, new IssueCommentJoinStubProvider());
        Test.startTest();
        Assert.isTrue(Test.isSoqlStubDefined(GithubIssues\_\_x.SObjectType));
        Assert.isTrue(queryIssueUtil.queryIssueToCommentJoinAndCheckForCommentId());
        Assert.areEqual(1, Limits.getQueries());
        Assert.areEqual(3, Limits.getQueryRows());
        Assert.areEqual(1, Limits.getAggregateQueries());
        Assert.isTrue(queryIssueUtil.queryIssueToCommentJoinAndVerifyResultSize(1, 2));
        Assert.areEqual(2, Limits.getQueries());
        Assert.areEqual(6, Limits.getQueryRows());
        Assert.areEqual(2, Limits.getAggregateQueries());
        Test.stopTest();
    }
}

/\*\*
 \*   SoqlStubProvider class that returns a mocked query result
 \*   for joined queries between the Github Issues object and
 \*   the associated Comments object.
 \*\*/

public with sharing class IssueCommentJoinStubProvider extends SoqlStubProvider {
    public override List<SObject> handleSoqlQuery(SObjectType sobjectType, String rawQuery, Map<String,Object\> binds) {
        if (sobjectType.equals(GithubIssues\_\_x.SObjectType)) {
            Assert.areEqual(0, binds.size());

            List<GithubIssues\_\_x> issues = new List<GithubIssues\_\_x>();
            List<Map<String,Object\>> commentMaps = new List<Map<String,Object\>>();

            Map<String, Object\> comment1 = new Map<String, Object\> {
                'Id' => 'x09xx000000brk9AAA'
            };
            Map<String, Object\> comment2 = new Map<String, Object\> {
                'Id' => 'x09xx000001brk9AAA'
            };

            commentMaps.add(comment1);
            commentMaps.add(comment2);

            List<IssueComments\_\_x> comments = (List<IssueComments\_\_x>) Test.createStubQueryRows(IssueComments\_\_x.SObjectType, commentMaps);

            Map<String, Object\> issueMap = new Map<String, Object\> {
                'Id' => 'x08xx000002HNZ6AAO',
                'Title\_\_c' => 'Sample Issue 1',
                'IssueComments\_\_r' => comments
            };

            GithubIssues\_\_x obj = (GithubIssues\_\_x) Test.createStubQueryRow(sobjectType, issueMap);

            issues.add(obj);
            return issues;
        }
        return null;
    }
}

/\*\*
 \*   SoqlStubProvider class that returns a mocked query result
 \*   for queries against the Github Issues object.
 \*\*/

public with sharing class IssueStubProvider extends SoqlStubProvider {
    public override List<SObject> handleSoqlQuery(SObjectType sobjectType, String rawQuery, Map<String,Object\> binds) {
        if (sobjectType.equals(GithubIssues\_\_x.SObjectType)) {
        Assert.areEqual(1, binds.size());
        Assert.areEqual('x08xx000002HNZ6AAO', binds.get('tmpVar1'));

            List<SObject> objs = new List<SObject>();
            Map<String, Object\> individualMap = new Map<String, Object\> {
                'Id' => 'x08xx000002HNZ6AAO'
            };
            GithubIssues\_\_x obj = (GithubIssues\_\_x) Test.createStubQueryRow(sobjectType, individualMap);
            objs.add(obj);
            return objs;
        }
        return null;
    }
}

/\*\*
 \*   Utility class that runs queries to be mocked 
 \*   in the Apex tests.  
 \*\*/

public with sharing class QueryIssueUtil {
    public boolean queryGithubIssuesAndCheckForId() {
        // BINDS WITH USER\_MODE DYNAMIC QUERY
        Map<String, Object\> binds = new Map<String, Object\>{'tmpVar1' => 'x08xx000002HNZ6AAO'};
        List<GithubIssues\_\_x> issues = Database.queryWithBinds('SELECT Id FROM GithubIssues\_\_x WHERE Id  = :tmpVar1', binds, AccessLevel.USER\_MODE);

        for (GithubIssues\_\_x issue : issues ) {
            if (issue.Id.equals('x08xx000002HNZ6AAO')) {
                return true;
            }
        }
        return false;
    }

    public boolean queryGithubIssuesAndVerifyResultSize(Integer size) {
        // BINDS WITH SYSTEM\_MODE STATIC QUERY
        String issueId = 'x08xx000002HNZ6AAO';
        List<GithubIssues\_\_x> issues = \[SELECT Id FROM GithubIssues\_\_x WHERE Id  = :issueId WITH SYSTEM\_MODE\];
        if(issues.size() == size) {
            return true;
        }
            return false;
    }

    public boolean queryIssueToCommentJoinAndCheckForCommentId() {
        // DYNAMIC QUERY
        List<GithubIssues\_\_x> issues = Database.query('SELECT Id, Title\_\_c, (SELECT Id FROM IssueComments\_\_r) FROM GithubIssues\_\_x WHERE Id = \\'003000000000000\\'', AccessLevel.USER\_MODE);


        for (GithubIssues\_\_x issue : issues) {
            List<IssueComments\_\_x> comments = issue.IssueComments\_\_r;
            System.debug(comments);
            if(!comments.get(0).Id.equals('x09xx000000brk9AAA') && !comments.get(1).Id.equals('x09xx000001brk9AAA'))return false;
        }
        return true;
    }

    public boolean queryIssueToCommentJoinAndVerifyResultSize(Integer parentSize, Integer childSize) {
        // STATIC QUERY
        List<GithubIssues\_\_x> issues = \[SELECT Id, Title\_\_c, (SELECT Id FROM IssueComments\_\_r) FROM GithubIssues\_\_x WHERE Id = '003000000000000' WITH USER\_MODE\];

        if(issues.size() == parentSize && issues.get(0).IssueComments\_\_r.size() == childSize) {
            return true;
        }
        return false;
    }

    public SObjectType getSObjectTypeForDynamicSoql(String name) {
        Schema.DescribeSObjectResult\[\] descResult = Schema.describeSobjects(new List<String\>{name});
        SObjectType type = descResult.get(0).getSobjectType();
        return type;
    }
}