Inner class test fixture pattern

Most Force.com tests require one or more related SObjects to be created in a known configuration. There are many ways this can be coded:

  • Inline in the static test method: but offers no re-use
  • Created by a static helper method in the test class: but not easy for the test method to access more than one of the created objects
  • Created by a separate fixture class: but hard to support all the variations needed and a lack of cohesion

In general I suggest the pattern illustrated below – using an inner test fixture class – is more effective. It addresses the problems listed above and is tolerant of change:

@isTest
private class XyzTest {
    // If variations in the Fixture are needed an enum is a clean way of identifying them
    private enum TestCase {
        Case1,
        Case2
    }
    private class Fixture {
        public Parent__c parent;
        public Child__c[] children;
        public Fixture(TestCase tc) {
            parent = new Parent__c(FirstName__c = 'Jane', LastName__c = 'Doe');
            insert parent;
            children = new Child__c[] {
                    new Child__c(Parent__c = parent.Id, Gender__c = 'Female'),
                    new Child__c(Parent__c = parent.Id, Gender__c = 'Male')
                    };
            insert children;
        }
        public void assertParent() {
            Parent actual = [select ... from Parent__c where Id = :parent.Id];
            // System.asserts go here
        }
        public void assertChildren() {
            Child__c[] actual = [select ... from Child__c where Id in :SobUtil.getIds(children)];
            // System.asserts go here
        }
    }
    @isTest
    static void testCase1() {
        Fixture fixture = new Fixture(TestCase.Case1);
        // Code here can access fields, perform assertions and invoke the fixture's assertions
    }
    @isTest
    static void testCase2() {
        Fixture fixture = new Fixture(TestCase.Case2);
        // Code here can access fields, perform assertions and invoke the fixture's assertions
    }
}

Avoiding a “Methods cannot be marked transient” compilation error

I recently needed to make an SObject field transient in a series of Apex wrapper objects used in a controller for a sequence of Visualforce wizard pages. Why is a whole other story.

Here is a simplified example of one of the wrappers:

public class ActionWrapper {
    public Action__c sob { get; private set; }
    public ActionWrapper(Action__c sob) {
        this.sob = sob;
    }
    // ...
}

Given the large amount of code that depended on these objects I wanted to hide the fact that the SObject field would be null each time a wizard page was posted and so tried code of this pattern (though with the SOQL done in bulk not in each get):

public class ActionWrapper {
    public transient Action__c sob {
        get {
            if (sob == null && sobId != null) {
                sob = [select ... from Action__c where Id = :sobId];
            }
            return sob;
        }
        private set {
            sob = value;
            sobId = sob.Id;
        }
    }
    private Id sobId;
    public ActionWrapper(Action__c sob) {
        this.sob = sob;
    }
    // ...
}

But this yields the error “Methods cannot be marked transient”: it looks like compilation of get or set without a body is handled differently from get or set with a body. Pretty discouraging…

The good news is that the following pattern solves the problem by separating the transient declaration from the get and set methods:

public class ActionWrapper {
    public Action__c sob {
        get {
            if (sobValue == null && sobId != null) {
                sobValue = [select ... from Action__c where Id = :sobId];
            }
            return sobValue;
        }
        private set {
            sobValue = value;
            sobId = sobValue.Id;
        }
    }
    private Id sobId;
    private transient Action__c sobValue;
    public ActionWrapper(Action__c sob) {
        this.sob = sob;
    }
    // ...
}

Accessing record type IDs in Apex code

Where you use record types on several objects, a convenient way to obtain the record type ID in Apex is needed. And as the record type ID requires a SOQL query to obtain the org-specific value, governor limits and efficiency come in to play too.

The pattern illustrated below allows the ID to be obtained using this simple and flexible call:

Id id = RT.getId(cve__Claim__c.SObjectType, RT.Name.ShortTermDisability);

The benefits of this approach are:

  • Only one SOQL query done (per server request) no matter how many record type IDs are referenced or where they are referenced e.g. inside a loop.
  • Avoids problems of typos in strings by using the compile-time checked SObjectType field and an enum for the Name values.
  • Handles the case where multiple objects use the same record type name well.
  • Adding a new record type just requires a single line to be added to the Name enum.
/**
 * RT stands for "RecordType".
 * Named cryptically as typical usage includes this class name twice.
 */
public class RT {
    /**
     * These (developer) names can apply to more than one SOBjectType.
     */
    public enum Name {
        ShortTermDisability,
        LongTermDisability,
        TermLife,
        WaiverOfPremium
    }
    private static final String SEPARATOR = '::::';
    private static Map<String, Id> CACHE;
    /**
     * Get the Id that can be set on or compared with an SOBject's RecordTypeId field.
     * Backed by a cache of all record type ids for the duration of a request.
     */
    public static Id getId(SObjectType sobType, Name developerName) {
        if (CACHE == null) {
            CACHE = new Map<String, Id>();
            for (RecordType rt :  [
	                select Id, SObjectType, DeveloperName
	                from RecordType
	                where DeveloperName in :getNames()
	                ]) {
                CACHE.put(rt.SObjectType + SEPARATOR + rt.DeveloperName, rt.Id);
            }
        }
        return CACHE.get(String.valueOf(sobType) + SEPARATOR + developerName.name());
    }
    private static Set<String> getNames() {
    	Set<String> names = new Set<String>();
    	for (Name name : Name.values()) {
    		names.add(name.name());
    	}
    	return names;
    }
}

Also check out GaryB’s Record Types approach.