Insert Custom Metadata for Unit Test
At time of writing, it is not possible to insert test custom metadata, unless you use the Metadata API which would also present a challenge in a test scenario. That said, you should not need to. Custom Metadata is Metadata and as such is not affected by the SeeAllData annotation. See this article dedicated to testing custom metadata.
New in Winter 19! Instantiate Custom Metadata Types in Apex
Example from the release notes...
How: In this example, the first method is instantiating a custom metadata record, but no records are inserted into memory. The second method retrieves a record, changes it, and returns it to the caller, but the change is not updated in the database.
public class CustomMetadataService {
public CustomMetadataService() {}
/**
* This method instantiates a custom metadata record of type MyCustomMetadataType__mdt
* and sets the DeveloperName to the input String.
* Note that the record is not inserted into the database,
* and would not be found by a SOQL query.
*/
public MyCustomMetadataType__mdt getCustomMetadataRecord(String myName) {
MyCustomMetadataType__mdt theRecord = new MyCustomMetadataType__mdt();
theRecord.DeveloperName = myName;
return theRecord;
}
/**
* This method retrieves a custom metadata record, changes a field, and returns it
* to the caller. Note that the changed record is not updated in the database.
*/
public MyCustomMetadataType__mdt getChangedCustomMetadataRecord(String myNewName) {
MyCustomMetadataType__mdt theRecord = [SELECT Id, DeveloperName from MyCustomMetadataType__mdt LIMIT 1];
theRecord.DeveloperName = myNewName;
return theRecord;
}
}
As stated above, you can't insert Custom Metadata via Apex, but you create instances of mock data via JSON deserialization.
public static SObject getMetadata(SObjectType metadataSObjectType, Map<String, Object> fields) {
/**
* @Version-1.0.0
* Created.
*/
Map<String, Object> jsonFields = new Map<String, Object> {
'attributes' => new Map<String, Object> {
'type' => metadataSObjectType.getDescribe().getName()
}
};
if(fields != null) {
jsonFields.putAll(fields);
}
return (SObject) JSON.deserialize(JSON.serialize(jsonFields), SObject.class);
}
Update
If you need to query Custom Metadata in an Apex Class, consider using a private, virtual, @TestVisible
method which returns queried Metadata. If I'm use Custom Metadata, often it's because I'm building some sort of framework out of an abstract class.
@TestVisible virtual Framework_Request__mdt[] getAllMetadata() {
return [
SELECT Id, MasterLabel, Request__c
FROM Framework_Request__mdt
WHERE Framework__c = :this.getType().getName()
ORDER BY Order__c ASC
];
}
public abstract Type getType();
// This Framework dynamically creates Requests from Metadata
public Result processRequests() {
Result result = new Result();
try {
for(Framework_Request__mdt metadata : this.getAllMetadata()) {
Type requestType = Type.forName(metadata.Request__c);
Object newInstance = requestType == null ? null : requestType.newInstance();
if(newInstance instanceof Request) {
Request request = (Request) newInstance;
request.setData(this.getData());
request.process();
}
}
result.setIsSuccess(true);
}
catch(Exception e) {
result.setException(e);
result.setIsSuccess(false);
}
return result;
}
Then when testing the Framework, you need need to create an implementation to test your abstract class. There you can pass in hard-coded Custom Metadata so you don't have to reply on Custom Metadata existing
@IsTest
public class Framework_Test {
public static SObject getMetadata(SObjectType metadataSObjectType, Map<String, Object> fields) {
Map<String, Object> jsonFields = new Map<String, Object> {
'attributes' => new Map<String, Object> {
'type' => metadataSObjectType.getDescribe().getName()
}
};
if(fields != null) {
jsonFields.putAll(fields);
}
return (SObject) JSON.deserialize(JSON.serialize(jsonFields), SObject.class);
}
public class Framework extends Framework {
public override Type getType() {
return Framework_Test.Framework.class;
}
override Framework_Metadata__c[] getAllMetadata() {
return new Framework_Metadata__c[] {
(Framework_Metadata__c) getMetadata(
Schema.Framework_Metadata__c.SObjectType,
new Map<String, Object> {
'Request__c' => SimpleRequest.class.getName()
}
),
(Framework_Metadata__c) getMetadata(
Schema.Framework_Metadata__c.SObjectType,
new Map<String, Object> {
'Request__c' => SpecialRequest.class.getName()
}
)
};
}
}
@IsTest
public static void testFramework() {
// Data
Framework_Test.Framework framework = new Framework_Test.Framework();
Test.startTest();
Result result = framework.processRequests();
Test.stopTest();
}
}