It's been fairly well established1, 2 that inserting/updating custom settings in a unit test hurts several aspects of the test:
- Makes tests take longer to execute
- Makes it hard to run tests in parallel
- Part of the hit on parallelism is the
UNABLE_TO_LOCK_ROWerrors that become fairly common
With that in mind, I'm trying to put together a generic proxy class (part of a larger, personal project) to substitute direct calls to custom settings like
MyCustomSetting__c.getInstance() with something like
Having the proxy class handle access and modification would allow us to set up custom setting instances in tests without the need for DML.
Handling the test portion is relatively simple, load data in the test method itself, and then it's available in the code being tested. The bit I'm stuck on is in normal operation.
In normal operation, we won't have data pre-loaded. We can pass the custom setting name (or the SObjectType, or the
.class). If we see (in the proxy class) that there is no pre-loaded data for the custom setting, how can we attempt to grab that data?
A few possible solutions I've come up with include (in no particular order):
- Figuring out what the parent type of any given Custom Setting is, so that we can call
parentType.getInstance()(static methods). Documentation suggests this might be
CustomSetting__c, but anonymous apex shows that this is not a valid type. A Custom Setting is a subclass of
SObjecthas no static methods (only instance methods)
- Make a dynamic query using the information we do have (which burns a query for every custom setting that is accessed, which is... not so desirable)
- Create and maintain separate proxy classes for each custom setting (if we know (statically) which custom setting we're being asked for, we can simply use
<MyCustomSettingName>.getInstance()). I'm hoping there's a way to avoid this and just have a single, more abstract class
- Have clients call a method to pass in available data, e.g.
CustomSettingProxy.load(MyCustomSetting__c.getInstance());, before calling
CustomSettingProxy.find('MyCustomSetting__c').getInstance();. It'd work, but I imagine it'd be a hard sell (why do I need to call getInstance() twice?)
I'd like to avoid queries, avoid dml, and avoid making more than one class. I'm looking for a way to access the application cache (which is different from the platform cache) dynamically. Alternatively, adding custom setting data to the application cache without using DML would get rid of the need for a proxy in the first place.