How to choose the best cloud platform for AI
Explore a strategy that shows you how to choose a cloud platform for your AI goals. Use Avenga’s Cloud Companion to speed up your decision-making.
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 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.
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.
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.
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 code
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
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 SObject
if 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
and basic test for it
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
BankInterestCalculationLogic class like following
and test like following
Voila! Now we have 100% coverage and test contexts for different logic branches are separated!
* US and Canada, exceptions apply
Ready to innovate your business?
We are! Let’s kick-off our journey to success!