New to the SF dev world so I am struggling a bit with setting up some unit tests on external objects. I have found very little info on this, most dating back a few years.
I did find a post here on SO where I have adapted some of the code to get a test working. This seems to do the trick, however, it is structured for only testing a single external object, where I have several I need to test in my unit test.
Here is my code structure so far. The idea behind it is that you can just have your class pass data through it normally, but you can also override it to pass the mocked data that I choose.
// QueryPassthrough.cls
public virtual inherited sharing class QueryPassthrough {
public static List<SObject> records(List<SObject> records) {
return instance.passThrough(records);
}
static QueryPassthrough instance = new QueryPassthrough();
@TestVisible static void setMock(QueryPassthrough mock) {instance = mock;}
protected virtual List<SObject> passThrough(List<SObject> records) {
return records;
}
}
-
// Test_EnterpriseUtilities.cls
@isTest
private class Test_EnterpriseUtilities {
class Mock extends QueryPassthrough {
final List<EntContact__x> externalContacts;
Mock(List<EntContact__x> externalContacts) {
this.externalContacts = externalContacts;
}
protected override List<SObject> passThrough(List<SObject> records) {
return externalContacts;
}
}
@isTest
static testmethod void getExternalId() {
Test.startTest();
createData();
String result = EnterpriseUtilities.GetExternalId('x0x3F00000HudxFQAR', 'EntContact__x');
Test.stopTest();
system.assertEquals('00T3F00000HudxFUAR', result, 'Expecting an ExternalId of 00T3F00000HudxFUAR from the mocked external contact');
}
static void createData() {
// Create External Contact
List<EntContact__x> mockExternalContacts = new List<EntContact__x>();
mockExternalContacts.add(
new EntContact__x(
Name__c = 'Jim Test',
ExternalId = '00T3F00000HudxFUAR'
)
);
QueryPassthrough.setMock(new Mock(mockExternalContacts) );
}
}
-
// EnterpriseUtilities.cls
@AuraEnabled(cacheable = true)
public static String GetExternalId(ID currentRecordId, String objName) {
String query = 'SELECT ExternalId FROM ' + objName + ' WHERE id = :currentRecordId LIMIT 1';
List<SObject> result = QueryPassthrough.records( Database.query(query) );
String externalId = String.ValueOf( result[0].get('ExternalId') );
return externalId != '' ? externalId : null;
}
While this works fine for the one external object I am mocking EntContact__x
, I need to be able to support multiple objects. It was suggested to possibly use Map<SObjectType, List<SObject>>
to handle multiples, but I am having trouble trying to figure out where to implement this.
My attempt, which failed, seems way off. Again, still trying to get the hang of this.
final Map<SObjectType, List<SObject>> mockedData;
Mock(Map<SObjectType, List<SObject>> mockedData) {
this.mockedData = mockedData;
}
protected override Map<SObjectType, List<SObject>> passThrough(Map<SObjectType, List<SObject>> records) {
return mockedData;
}
// Fails with
@Override specified for non-overriding method: Map<Schema.SObjectType,List<SObject>> Test_EnterpriseUtilities.Mock.passThrough(Map<Schema.SObjectType,List<SObject>>)
Can anyone point out how I should implement the Map<SObjectType, List<SObject>>
? End goal here is for my test class to be able to mock multiple external objects, where right now it is structured only to support the one.
Update:
Based on Answer
@isTest
private class Test_EnterpriseUtilities {
class Mock extends QueryPassthrough {
final Map<SObjectType, List<SObject> > cache;
public Mock() {
cache = new Map<SObjectType, List<SObject> >();
}
public Mock setDataStore(List<SObject> records) {
cache.put(records.getSObjectType(), records);
return this;
}
protected override List<SObject> passthrough(List<SObject> records) {
return cache.get(records.getSObjectType() );
}
}
}
/**
* Create test data
*/
static void createData() {
// Test External Contact
List<EntContact__x> mockExternalContacts = new List<EntContact__x>();
mockExternalContacts.add(
new EntContact__x(
Name__c = 'Jim Test',
ExternalId = '00T3G5430HudxFUAR'
)
);
QueryPassthrough.setMock( new Mock(mockExternalContacts) );
}
I may be missing something else here, but it is complaining about a constructor not being defined with these changes:
Constructor not defined: [Test_EnterpriseUtilities.Mock].<Constructor>(List<EntContact__x>) (115:35)
.
I left the QueryPassthrough.cls
file unchanged and just made the update to the test.