function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
Mario CMario C 

Test class with Custom Metadata Types (Support_Setting__mdt)

Hi All,

I've followed a tutorial about excluding specific domains in email to case, so that if an email from a specific domain is sent to the email2case email, a case won't get created. The application works great in Sandbox but I am struggling to move it to production as the test class seems to require some test entry for the custom metadata type and I am not really sure how to include that in the test class. 

Trigger:
//Tins trigger wiLL. be used to KiLL emaiLs coming via E2C and with certain domain names 2 
trigger AutoE2CCaseDeletion on Case (before insert) { 
    System.debug('Entered Kill Case trigger'); 
    SSK_RestrictedE2CDomains.killEmailToCase(Trigger.New); 
}



Here is the main class:
public with sharing class SSK_RestrictedE2CDomains {
	private static String SSK_RestrictedE2CDomains {
	get{
		return 'Restriced_E2C_Domains';
		
	}
}

private static Set<String> getSupportSetting(String settingName){
	Support_Setting__mdt supportSetting = [
	SELECT Value__c
	FROM Support_Setting__mdt
	WHERE DeveloperName = :settingName
	];
	

	Set<String> settingValues = new Set<String>();

	//settingValues.addAll(supportSetting.Value__c.split(','));
	return settingValues;
}

//Method to kiLL EmaiLs coming in from restricted Domains (E2C) 
public static void killEmailToCase (List<Case> lstCases){ 
	System.debug('killEmailToCase method successfully called'); 
	for(Case newCase: lstCases){ System.debug('Case ID: ' + newCase.Id); 
	System.debug('Case Origin: ' + newCase.Origin); 
	System.debug('Case From/Supplied/Web Email: ' + newCase.SuppliedEmail); 
	System.debug('Record Type name is: ' + newCase.RecordType.DeveloperName); 


//Read the "Restricted E2C Domains" from the Custom Metadata Types Labelled "Support Settings" 
Set<String> restrictedE2CDomains = getSupportSetting(SSK_RestrictedE2CDomains); 
if(newCase.SuppliedEmail != NULL && newCase.SuppliedEmail != 'email2casesmith@gmail.com'){ 
if(newCase.Origin == 'Email' && newCase.SuppliedEmail != NULL && newCase.SuppliedEmail.contains('@')) { 
//SpLit the EmaiL with DeLimiter as 1@' 
//So john.doe@gmaiL.com returns a List - ['fijohn.doe', 'gmaiL.com'] 
//Here the second index wiLL point to the Domain Name which is [1] 
List<String> emailParts = newCase.SuppliedEmail.split('@'); 
if(restrictedE2CDomains.contains(emailParts[1])){ 
	System.debug('Problematic case found and shouldnt be created'); 
	newCase.addError('Creation of cases with these domains are not allowed'); 
} 
} 
} 
} 
}		
}
TestClass1
@isTest 
private class tstE2CDomainNoKill {
	static testMethod void notKillCaseE2C_valid_domain(){

	Account newAcc = new Account();
	newAcc.Name = 'Test Account';
	Insert newAcc;

	Case newCase = new Case();
	newCase.AccountId = newAcc.Id;
	newCase.SuppliedEmail = 'test@gmail.com';
	newCase.Origin = 'Email';
	Insert newCase;
	System.assertNotEquals(NULL, newCase.Id);

	Case newCase2 = new Case();
	newCase.AccountId = newAcc.Id;
	newCase.SuppliedEmail = 'email2casesmith@gmail.com';
	newCase.Origin = 'Email';
	Insert newCase2;
	System.assertNotEquals(NULL, newCase2.Id);


		
	}
}

The above test class does fail and show the following text:

System.DmlException: Insert failed. First exception on row 0; first error: CANNOT_INSERT_UPDATE_ACTIVATE_ENTITY, AutoE2CCaseDeletion: execution of BeforeInsert

caused by: System.QueryException: List has no rows for assignment to SObject

Class.SSK_RestrictedE2CDomains.getSupportSetting: line 10, column 1
Class.SSK_RestrictedE2CDomains.killEmailToCase: line 33, column 1
Trigger.AutoE2CCaseDeletion: line 4, column 1: []
Any help/suggestion would highly be appreciated.

Thanks!




 

mirkimirki
Hi,

Deploy the metadata type and values as part of the deployment. Custom metadata types and their values are deployable as they are considered configuration. The values are visible to test methods even if seeAllData is not set to true.

For more information:
https://help.salesforce.com/articleView?id=custommetadatatypes_changesets.htm&type=5

Regards,
mirki
Alain CabonAlain Cabon
Hi,

Did you deploy your metadata type at first in production?

By default, Apex tests don’t see any data that they don’t create themselves. But as that topic states, there are exceptions: metadata objects and objects used to manage your organization. 

https://developer.salesforce.com/blogs/engineering/2015/05/testing-custom-metadata-types.html

https://help.salesforce.com/articleView?id=custommetadatatypes_changesets.htm&type=5
 
Mario CMario C
Hi Alain and Mirki,

I still do not have enough coverage to move it to production. The error is being triggered from line 10 and 33; both lines are linked to the custom metadata types... 
mirkimirki
Are you deploying the metadata type and the values at the same time? They should be already in production or be deployed at the same time.
Mario CMario C
My test classes currently  cover up to 58% of the class, so I can't move anything to production untill the coverage is at least 75%.  
mirkimirki
If you are encountering this issue in sandbox, try adding the actual configuration values to the metadata. This will increase the coverage in sandbox. Then, when you deploy both the metadata type + config values + the classes to production, the test class will run successfully (since the configuration values are present) and thus, you should be able to deploy to production.
Alain CabonAlain Cabon
You should deploy the new field Value__c alone (or/and the object Support_Setting__mdt) without your trigger.
v varaprasadv varaprasad
Hi 

Try this : 

 
private class tstE2CDomainNoKill {
	static testMethod void notKillCaseE2C_valid_domain(){
    //Query custom metadata here
	
	Support_Setting__mdt supportSetting = [
	SELECT Value__c
	FROM Support_Setting__mdt
	WHERE DeveloperName = :settingName
	];
	
	//Instead off setting name here pass record name
	set<string> mdtsettings =SSK_RestrictedE2CDomains.getSupportSetting('settingName'); 
	system.debug('==mdtsettings=='+mdtsettings);
	
	Account newAcc = new Account();
	newAcc.Name = 'Test Account';
	Insert newAcc;

	Case newCase = new Case();
	newCase.AccountId = newAcc.Id;
	newCase.SuppliedEmail = 'test@gmail.com';
	newCase.Origin = 'Email';
	Insert newCase;
	System.assertNotEquals(NULL, newCase.Id);

	Case newCase2 = new Case();
	newCase.AccountId = newAcc.Id;
	newCase.SuppliedEmail = 'email2casesmith@gmail.com';
	newCase.Origin = 'Email';
	Insert newCase2;
	System.assertNotEquals(NULL, newCase2.Id);
   }
		
	}



Hope this helps you!
If my answer helps resolve your query, please mark it as the 'Best Answer' & upvote it to benefit others.

Thanks
Varaprasad
@For Salesforce project Support: varaprasad4sfdc@gmail.com

Salesforce latest interview questions  :
https://www.youtube.com/channel/UCOcam_Hb4KjeBdYJlJWV_ZA?sub_confirmation=1

 
Mario CMario C
Hi Vraprasad,

Unfortunately this is not working. I have used this code:
@isTest 
private class tstE2CDomainNoKill {
	static testMethod void notKillCaseE2C_valid_domain(){

   //Query custom metadata here
	
	Support_Setting__mdt supportSetting = [
	SELECT Value__c
	FROM Support_Setting__mdt
	WHERE DeveloperName = 'Restricted_E2C_Domains'
	];
	
	//Instead off setting name here pass record name
	set<string> mdtsettings =SSK_RestrictedE2CDomains.getSupportSetting('Restricted_E2C_Domains'); 
	system.debug('==mdtsettings=='+mdtsettings);

	Account newAcc = new Account();
	newAcc.Name = 'Test Account';
	Insert newAcc;

	Case newCase = new Case();
	newCase.AccountId = newAcc.Id;
	newCase.SuppliedEmail = 'test@gmasil.com';
	newCase.Origin = 'Email';
	Insert newCase;
	System.assertNotEquals(NULL, newCase.Id);

	Case newCase2 = new Case();
	newCase.AccountId = newAcc.Id;
	newCase.SuppliedEmail = 'email2casesmith@gmsail.com';
	newCase.Origin = 'Email';
	Insert newCase2;
	System.assertNotEquals(NULL, newCase2.Id);


		
	}
}

I still get an error in line 14:
Method is not visible: Set<String> SSK_RestrictedE2CDomains.getSupportSetting(String)

Furthermore, I replaced settingname with the name of the support setting record, is thata correct?

Please let me know.

Thanks,
Mario

 
v varaprasadv varaprasad
Hi,

Use @TestVisible annotation in the method like : 
 
@TestVisible private static Set<String> getSupportSetting(String settingName){
	Support_Setting__mdt supportSetting = [
	SELECT Value__c
	FROM Support_Setting__mdt
	WHERE DeveloperName = :settingName
	];
	

	Set<String> settingValues = new Set<String>();

	//settingValues.addAll(supportSetting.Value__c.split(','));
	return settingValues;
}



Hope this helps you!
If my answer helps resolve your query, please mark it as the 'Best Answer' & upvote it to benefit others.


Please follow below salesforce Best Practice for Test Classes :-

1. Test class must start with @isTest annotation if class class version is more than 25
2. Test environment support @testVisible , @testSetUp as well
3. Unit test is to test particular piece of code working properly or not .
4. Unit test method takes no argument ,commit no data to database ,send no email ,flagged with testMethod keyword .
5. To deploy to production at-least 75% code coverage is required
6. System.debug statement are not counted as a part of apex code limit.
7. Test method and test classes are not counted as a part of code limit
9. We should not focus on the  percentage of code coverage ,we should make sure that every use case should covered including positive, negative,bulk and single record .
Single Action -To verify that the the single record produces the correct an expected result .
Bulk action -Any apex record trigger ,class or extension must be invoked for 1-200 records .
Positive behavior : Test every expected behavior occurs through every expected permutation , i,e user filled out every correctly data and not go past the limit .
Negative Testcase :-Not to add future date , Not to specify negative amount.
Restricted User :-Test whether a user with restricted access used in your code .
10. Test class should be annotated with @isTest .
11 . @isTest annotation with test method  is equivalent to testMethod keyword .
12. Test method should static and no void return type .
13. Test class and method default access is private ,no matter to add access specifier .
14. classes with @isTest annotation can't be a interface or enum .
15. Test method code can't be invoked by non test request .
16. Stating with salesforce API 28.0 test method can not reside inside non test classes .
17. @Testvisible annotation to make visible private methods inside test classes.
18. Test method can not be used to test web-service call out . Please use call out mock .
19. You can't  send email from test method.
20.User, profile, organization, AsyncApexjob, Corntrigger, RecordType, ApexClass, ApexComponent ,ApexPage we can access without (seeAllData=true) .
21. SeeAllData=true will not work for API 23 version eailer .
22. Accessing static resource test records in test class e,g List<Account> accList=Test.loadData(Account,SobjectType,'ResourceName').
23. Create TestFactory class with @isTest annotation to exclude from organization code size limit .
24. @testSetup to create test records once in a method  and use in every test method in the test class .
25. We can run unit test by using Salesforce Standard UI,Force.com IDE ,Console ,API.
26. Maximum number of test classes run per 24 hour of period is  not grater of 500 or 10 multiplication of test classes of your organization.
27. As apex runs in system mode so the permission and record sharing are not taken into account . So we need to use system.runAs to enforce record sharing .
28. System.runAs will not enforce user permission or field level permission .
29. Every test to runAs count against the total number of DML issued in the process .

Thanks
Varaprasad
@For SFDC Support: varaprasad4sfdc@gmail.com

Salesforce latest interview questions  :
https://www.youtube.com/channel/UCOcam_Hb4KjeBdYJlJWV_ZA?sub_confirmation=1

 
swastika raj 6swastika raj 6
Hi,

You can use getter and setter for custom meta data. Inside the test method, you have to assign values to that property. It will not check the record exists in the custom metadata.
 
public with sharing class SSK_RestrictedE2CDomains {
	
	private final static String SSK_RestrictedE2CDomainsValue = 'Restriced_E2C_Domains';
	@testVisible
    private static String supportSetting {
        get{
            if(supportSetting == null){
                Support_Setting__mdt supportSettingData = [SELECT Value__c FROM Support_Setting__mdt WHERE DeveloperName = :SSK_RestrictedE2CDomainsValue][0];
				supportSetting = supportSettingData.Value__c;
            }
            return supportSetting;
        }
        private set;
    }
	
	@testVisible
	private static Set<String> getSupportSetting{
        get{
            if(getSupportSetting == null){
                getSupportSetting = new Set<String>();
                getSupportSetting.put(supportSetting.split(','));
            }
            return getSupportSetting;
        }
        private set;
    }	


//Method to kiLL EmaiLs coming in from restricted Domains (E2C) 
public static void killEmailToCase (List<Case> lstCases){ 
	System.debug('killEmailToCase method successfully called'); 
	for(Case newCase: lstCases){ System.debug('Case ID: ' + newCase.Id); 
	System.debug('Case Origin: ' + newCase.Origin); 
	System.debug('Case From/Supplied/Web Email: ' + newCase.SuppliedEmail); 
	System.debug('Record Type name is: ' + newCase.RecordType.DeveloperName); 


//Read the "Restricted E2C Domains" from the Custom Metadata Types Labelled "Support Settings" 
Set<String> restrictedE2CDomains = getSupportSetting; 
if(newCase.SuppliedEmail != NULL && newCase.SuppliedEmail != 'email2casesmith@gmail.com'){ 
if(newCase.Origin == 'Email' && newCase.SuppliedEmail != NULL && newCase.SuppliedEmail.contains('@')) { 
//SpLit the EmaiL with DeLimiter as 1@' 
//So john.doe@gmaiL.com returns a List - ['fijohn.doe', 'gmaiL.com'] 
//Here the second index wiLL point to the Domain Name which is [1] 
List<String> emailParts = newCase.SuppliedEmail.split('@'); 
if(restrictedE2CDomains.contains(emailParts[1])){ 
	System.debug('Problematic case found and shouldnt be created'); 
	newCase.addError('Creation of cases with these domains are not allowed'); 
} 
} 
} 
} 
}		
}

@isTest 
private class tstE2CDomainNoKill {
	static testMethod void notKillCaseE2C_valid_domain(){

	Set<String> settingToAssign = new Set<String>{'a','b','c'};
	SSK_RestrictedE2CDomains.getSupportSetting = settingToAssign;
	......
	.......
	
	Test.StartTest();
	SSK_RestrictedE2CDomains.killEmailToCase(listCases);
	Test.StopTest();

		
	}
}