I'm not saying this will solve your problem as I can tell you are holding back underlying complexities but it is an alternative to Test.loadData
where you need a lot of control over your other-unmockable-by-DML test data.
Production class
public class MyProdClass {
public interface IUltimateAccount {
Account get();
}
public class ProdUltimateAccount implements IUltimateAccount {
public Account get() {
return [select ... from Account ... ]; // your logic here
}
// default the variable representing the interface to the PROD version. Testmethod can override
@TestVisible private IUltimateAccount iUltimateAccount = new ProdUltimateAccount();
// constructor
public MyProdClass() {}
.... somewhere where you need the ultimate (highest) account
public void doSomethingUseful() {
Account theUltimateAcct = iUltimateAccount.get();
.. and exploit it
}
}
Test Class and Method
@isTest
private with sharing MyTestClass {
public class IMockUltimateAccount implements MyProdClass.IUltimateAccount {
String useCase;
public IMockUltimateAccount(String useCase) {this.useCase = useCase;}
public Account get() {
Map<String,Account> useCaseToAccountMap = new Map<String,Account> {
'usecase1' => new Account(fldA = 'foo', ...),
'usecase2' => new Account(fldA = 'bar', ...),
...
};
return useCaseToAccountMap.get(this.useCase);
}
}
...
@isTest
private static void testMyStuff() {
MyProdClass cls = new MyProdClass();
cls.iUltimateAccount = new IMockUltimateAccount('usecase1');
// prod class uses testmethod's interface to return usecase-specific mocked ultimate Account
cls.doSomethingUseful();
system.assert(somethingUseful);
}
}
Notes
- The testmethod, if it needs to mock specific auto-numbers or ID fields, use
Json.deserialize
instead of the Account constructors as shown
- The only thing this technique does is avoid the need to actually insert a mocked record into the database, instead, you return the sObject as if it had been retrieved via SOQL
- If you need to build a hierarchy of mocked Accounts, this may get complex
- You have to anticipate everywhere in the PROD class where the ultimate Account is fetched and ensure all those use cases go through the interface's
get()
method.
Test.loadData
.IUltimateParent
with a single methodget()
. Then, in PROD code, implement a concrete implementation of the method that fetches the PROD master Account. In the testmethod, create a separate implementation that returns a mocked Account. The testmethod sets the value of the PROD's interface variable to point at the test interface's implementation