Introduction
Quite often you need to test a piece of functionality that processes date fields in Salesforce.com. Every object in Salesforce.com has system fields - CreatedDate and LastModifiedDate - which signify when a record was created, and when it has been updated the last time.A Few Possible Approaches
Imagine, you are writing a test for a method that must return the most recently created Account. How would you do that? Unfortunately, Force.com does not allow programmatic modification of such system fields. So, the following code snippet simply will not work:You may try to insert two records one after another, but they will all have the same CreatedDate, thus this approach will not work either.
One might decide to put an artificial delay into the code, so that records are guaranteed to be inserted at different times.
This approach is pretty hackish. First of all, Force.com does not have any sleep function that means you have to simulate it. Secondly, this can easily result into the 'Too many script statements' exception. Finally, unit tests should not depend on such time-based constructs.
There can be another temptation of preparing a test environment by manually inserting records which will be later on used by a test. This is hardly an optimal approach either, as it makes a test expect a system to be in a known state, which makes it very brittle.
Test.loadDate() To The Rescue
Fortunately, Salesforce.com Winter '13 introduces a method called Test.loadData(). The method loads test data from a Static Resource, which can be just a CSV file. What is important for us, it allows setting System Fields, such as CreatedDate, and LastModifiedData, but not SystemModstamp.
So, the resulting test code will look like this:
Given that we have a Static Resource similar to the one below:
Static Resources
A static resource can be easily created in the Develop Section ([Your Name] -> Setup -> Develop -> Static Resources). Then, you can download it by using the Force.Com IDE or any other tool. Alternatively, you can manually create it locally in the 'staticresources' directory of your project, and deploy it to your Salesforce.com organisation. You will have to create both a resource file and a meta file.
In case, you wonder how Static Resources are different from manual insertion of records into a Salesforce.com organisation, there are a few points. First of all, it is for a test to insert data by calling Test.loadDate(), so a developer has control over it. Secondly, unlike some pre-loaded data, Static Resources can be distributed and put into your Source Control Management system.
In case, you wonder how Static Resources are different from manual insertion of records into a Salesforce.com organisation, there are a few points. First of all, it is for a test to insert data by calling Test.loadDate(), so a developer has control over it. Secondly, unlike some pre-loaded data, Static Resources can be distributed and put into your Source Control Management system.
One Important Remark
A value of the CreatedDate must be always in past.
What About LastModifiedDate?
If you want to test a method that deals with the LastModifiedDate you can use a similar approach. However, your static resource must contain both CreatedDate, and LastModifiedDate. Otherwise, there will be an exception thrown saying that a LastModifiedDate cannot be earlier than a CreatedDate. Indeed, if you do not specify a value of CreatedData, Salesforce.com will use a date at the time of record insertion.Be Careful With Custom Fields And Managed Packages
When a custom field is a part of a Managed Package its name is prepended with a package namespace prefix. It is done automatically by the platform, so typically a developer does not have to care about that. However, when you are inserting data by calling Test.loadData(), you have to prefix field names manually.
This may cause a bit of inconvenience, when you are developing code in one Salesforce.com organisation, where such code is not a part of any package, and have another organisation for building a package. You can solve this problem by using two branches in your Source Code Management system, such that one branch is used for keeping code which is in development, while the other one is used for code which is released in a managed package.
Source Code
You can file all the source code in the my Github repository.
Mike Borozdin, Software Developer
email: mike.borozdin at cloudreach

No comments:
Post a Comment