Skip to main content

Salesforce Spring 16 Release - CreatedDate and Apex Unit Tests


(
Note that this blog post refers to functionality that is intended to be made available in the Spring 16 release of Salesforce, but features may be removed prior to the Spring 16 go-live date, so you may never see this in the wild!)

INTRODUCTION

Anyone who has written a reasonable amount of Apex unit tests is likely to have butted up against the shortcoming that the CreatedDate is set when a record is inserted into the Salesforce database. While at first glance this may not seem to be such a huge issue, consider the scenario of a custom Visualforce page, maybe for use in a dashboard, that displays the 10 most recent cases:
Screen Shot 2016 01 03 at 14 58 50
The controller is about as straightforward as it can be - simply querying back the records from the Salesforce database:
?
1
2
3
4
5
6
7
8
9
10
11
public class RecentCasesController
{
    public List<Case> getRecentCases()
    {
        return [select id, CaseNumber, Subject, Account.Name, Contact.Name,
                CreatedDate
                from Case
                order by CreatedDate desc
                limit 10];
    }
}
while the page is equally straightforward, simply iterating the records in a pageblocktable:
?
1
2
3
4
5
6
7
8
9
10
<apex:page controller="RecentCasesController">
    <apex:pageBlock title="10 Most Recent Cases">
        <apex:pageBlockTable value="{!recentCases}" var="cs">
            <apex:column value="{!cs.subject}"/>
            <apex:column value="{!cs.Account.Name}" />
            <apex:column value="{!cs.Contact.Name}" />
            <apex:column value="{!cs.CreatedDate}" />
        </apex:pageBlockTable>
    </apex:pageBlock>
</apex:page>

A TESTING PROBLEM

Testing this in the Winter 16 release (and earlier), testing this functionality meant a compromise, such as:
  • Inserting a number of records and ensuring that only 10 of them were returned, but being unable to predict which 10 this would be. This is because the CreatedDate field has second granularity, and if there are a number of records inserted in the same second, there is no guarantee of the order they will be returned in when the query is ordered by the CreatedDate. The Salesforce database will do the least amount of work to execute the query, and there’s nothing you can do to affect it. From a unit testing perspective, unless you can 100% guarantee the order of the results, asserting for a particular order makes a test fragile.
  • Adding an autonumber field to the case sobject so that you can rely on that to guarantee the ordering. This is a classic example of changing your implementation to satisfy your unit tests, which if nothing else is annoying to have to resort to.
  • Trying to kill some time to allow the second to tick over in between record inserts, by looping a lot and generating debug statements for example. There are a couple of problems with this approach. First, it is fragile, as you have no control over how much time would be burned this way. All you can do is hope that the performance you have seen in the past continues, which can’t give much confidence. More importantly, it is evil, as you are consuming shared resources for no good reason.
  • Provide some form of dependency injection, probably via a @TestVisible private property, to allow your test to inject the list of cases that should be returned as a result. This mechanism means that all you are really testing is that the controller returns the list of cases you asked it to, bypassing the query that will be executed in production. Writing code that solely allows your tests to complete successfully is usually an indication that something is awry.

ONE DOES SIMPLY SET THE CREATEDDATE

In the Spring 16 release this is all set to change (although it may not - see the note at the top of this blog). The new Test.setCreatedDate(Id, DateTime) method allows you to change the CreatedDate once a record is inserted.
For my recent cases page, I can now write a test case to verify that only the 10 most recent cases are returned, by setting the CreatedDate for each case record after I’ve inserted them in the database:
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
@isTest
private class RecentCasesController_Test
{
    @isTest
    static void TestGetRecentCases()
    {
        /* setup */
        Account acc=new Account(Name='Unit Test');
        insert acc;
         
        Contact cont=new Contact(FirstName='Unit',
                                 LastName='Tester');
        insert cont;
         
        List<Case> cases=new List<Case>();
        for (Integer idx=1; idx<=20; idx++)
        {
            Case cs=new Case(Subject='Test Case ' + idx,
                             AccountId=acc.Id,
                             ContactId=cont.Id);
            cases.add(cs);
        }
                              
        insert cases;
         
        // now set the created date for each case - the first case
        // in the list will be the most recent, the second case the
        // second most recent, and so on
        for (Integer idx=1; idx<=20; idx++)
        {
            DateTime created=System.now().addDays(-(idx*10));
            Test.setCreatedDate(cases[idx-1].Id, created);
        }
     
        /* execute */
        RecentCasesController ctrl=new RecentCasesController();
        List<Case> recentCases=ctrl.getRecentCases();
        /* verify */
  
        // should be 10 cases
        System.assertEquals(10, recentCases.size());
         
        // should be the first 10 inserted, in that order
        for (Integer idx=0; idx<10; idx++)
        {
            System.assertEquals(recentCases[idx].Id, cases[idx].Id);
        }
    }
}

FINAL THOUGHTS

The ability to set the created date is a much needed addition to the Salesforce platform testing framework, and one that will allow production code to be properly tested, and allow some workarounds/terrible hacks to be retired.
It would be cool to be able to set the CreatedDate when constructing the sObject, prior to insertion, but I’d imagine this would require a ton of changes to the Salesforce database layer and isn’t going to happen. I foresee thousands of test fixture classes that insert a record and then change its CreatedDate!
Its a shame that at the moment you can only set the CreatedDate of a single record per call, but hopefully we’ll get some bulk capability in the future. The Salesforce platform approach is typically to make things doably difficult, then add the bells and whistles.
Finally, the documentation doesn’t mention any effects on limits and my testing with the code above bears this out, which is always good.

Comments

Popular posts from this blog

Track Field History for more than 20 fields - Salesforce

All of us would have come across a situation when we need to track more than 20 fields for an object in salesforce. We have raised this Idea around 8 years ago in the success community. But sill it has't implemented by salesforce. But for now, we can achieve it partially with the following workaround. Approach: This approach uses a custom Text field which stores values of multiple other individual fields. Then enabling field history tracking of this field would allow you to track changes for multiple sets of other individual fields. Thus even though remaining within the count limit 20, yet track changes of more than 20 fields. Let us in this example take “Account ”  object and apply the steps to track change in Account Name, Phone, Parent Account and Billing Address all together. Steps: Step 1:  Add a new custom field. Setup -> Customize -> Accounts -> Fields Create a new Text (255) field “ Track FieldHistory ” (Or give any other n...

Customize the columns in the Items to Approve section on home page

We can customize the items to approve section with the help of custom visualforce page. All you need to do is create the below page with your object and respected fields to be displayed and then add the page to a new home page component. Page: <apex:page controller="itemstoApprovecontroller" sidebar="false" showHeader="false">     <apex:form >         <apex:pageBlock title="Incidents/Service Request To Approve">             <apex:pageBlockTable value="{!items_to_approve}" var="item_to_approve">                 <apex:column headerValue="Action" width="160 px" >                                     <apex:commandLink target="_top" value="Reassign |" action="{!REASSIGNnavigation}" style="text-decoration:none;color: #015ba7;" styleClass="cactionLink">   ...

Kanban view for Lightning

Tired of list views? Looking for a dynamic views to show your cases or opportunities in all new way? Here we go,  Salesforce introduced Kanban views for us to have better visibility  of our cases/opportunities and their journey from opening to closure. A case kanban allows you to visually summarize all of the cases for your agents,  by status or priority. It's not only a board, but also a  drag and drop  tool that will help agents keep their cases moving towards resolution. Similarly an opportunity Kanban display opportunities from a particular sales path Let's take a closer look at what all we can do with Kanban Track a Deal with Path Display opportunities by Sales path Move an Opportunity to the Next Stage Take Action on Your Records