Get 100% Code Coverage for Salesforce Custom Metadata Based Decisions

Introduction

Many applications use configuration data. Configuration data might be relevant to the entire organization, or subset of users or might be different for each user. In other words, it is possible to define some global configuration relevant to the whole organization or some minor configuration which is relevant to some small departments. In this article we will focus only on global configuration settings.

There are different possible solutions for storing configuration data. Configuration data can be stored in:

  • Custom Objects,
  • Custom Settings and
  • Custom Metadata records.

Custom objects are not usually used for storage of configuration data but in some extreme edge-cases scenarios like if there is a need to have an encrypted text field, custom objects might be also used for configuration data since neither custom settings nor custom metadata support encrypted fields feature.

In most cases, however, custom settings or custom metadata are used.Metadata Salesforce

Deprecated List custom settings and custom metadata comparison

Custom Metadata is a feature delivered back in Summer ‘15 release. It is similar to (Deprecated) List Custom Settings but it has several key differences. List Custom settings are deprecated since Spring ’18 release and custom metadata functionality should be used instead of them.

Similarities

 

  1. Both List Custom Settings and Custom Metadata resemble Custom Objects. They contain table values and resemble database tables.
  2. Both List Custom Settings and Custom Metadata allow creation of Checkbox, Date, Date\Time, Email, Number, Percent, Phone, Text, Text Area, URL fields.
  3. Admin Users can create both List Custom Settings and Custom
  4. Metadata definition using Salesforce native UI capabilities as well as deploy List Custom Settings and Custom Metadata definition using Ant Migration Tool or SFDX the same way custom objects are deployed.
  5. Users can create both List Custom Settings data and Custom Metadata records using Salesforce native UI capabilities. However, since List Custom Settings are deprecated, this old functionality must be enabled on new environments if needed.
  6. You can select Visibility for both Custom Settings and Custom Metadata to have it either Public or Protected. Protected Visibility prevents managed package users from accessing the custom settings or custom metadata.

Differences

 

List Custom Settings (deprecated) Custom Metadata
List Custom Settings data can be constructed and inserted by Apex code. Custom Metadata records cannot be neither constructed nor inserted by Apex code.
List Custom Settings data cannot be deployed Custom Metadata records can be deployed
List Custom Settings support Currency fields. Custom Metadata support Picklists, Metadata Relationships (similar to Custom Objects lookups) and Long Text Area Fields.
There are no specific Custom Settings fields values features related to managed package If you develop a managed package you can control if Custom Metadata Field values can be changed by package user or by package developers

 

Usually Custom Metadata records are very attractive to developers since they can be deployed.

So it is also better to use Custom Metadata configuration than Custom Settings configuration since Custom Metadata records can be deployed and during migration some default settings might be migrated from one organization to another with metadata itself. Since Spring ’18 List Custom Settings are deprecated, so Custom Metadata became the default option.

However, the fact that custom metadata records cannot be constructed or inserted in Apex code brings obstacles to the process of writing unit tests to cover business logic depending on the custom metadata record values. Let’s discuss this more deeply considering the following example.

Example

 

Assume we need to build an application for bank interest rates calculation.

Some banks might use simple interest rate calculation, another might use compound interest rate calculation.

We might be interested in building an application which would allow us to use any of these two calculations based on configuration.

Assume we have created a custom metadata type Custom_Metadata__mdt and created a picklist field on it Custom_Field__c and created a custom metadata record with DeveloperName value Default which we are going to use to determine which calculation to use.

Assume we created some simple class BankInterestCalculationLogic with the following codeSalesforce Custom Metadata
We might actually employ a strategy pattern to decide which formula to use for interest rate calculation, but for sake of simplicity let’s consider this piece of code. Anyway, even using a strategy pattern we would have some method to determine which strategy to use.

The main focus here is how to write unit tests which would use different strategies based on current value in the custom metadata record.

Simplest try to write test class for this might look like following
Salesforce Custom Metadata 2
This test class will succeed both in cases when the Custom_Field__c field value in the record is 1 or 2 but will fail with error 

System.QueryException: List has no rows for assignment to SObjectif someone deletes this custom metadata record.

However, the main problem is one of the branches of conditional statement will not be covered. If the value is 1 then the branch implementing the compound interest rate calculation will not be covered. Otherwise if the value is 2 then the branch implementing the  simple interest rate would not be calculated.

Unfortunately official documentation doesn’t provide a solution how 100% of coverage can be achieved in this case.

We can’t insert custom metadata records (despite the fact that users may play with them and delete and modify the data in the custom metadata record).

We can’t even construct a custom metadata record to use it inside Test.loadData.

However, there is a solution to this problem.

We might overcome this obstacle by using JSON.deserialize method.

Let’s generate a class to deal with Custom Metadata records
Salesforce Custom Metadata 4
and basic test for itSalesforce Custom Metadata 5

Basic test gives 100% coverage for the CustomMetadataDAO class and also provides a utility method to set custom metadata records for the tests.

Look how can we use it to get 100% coverage to cover both interest rates calculations.

Let’s refactor our BankInterestCalculationLogic class like following
and test like following
Salesforce Custom Metadata 7

Configure data in Salesforce better
Get in touch with us using the contact form below. We’ll get back to you shortly.
Back to overview