Showing posts with label unit test. Show all posts
Showing posts with label unit test. Show all posts

Tuesday, March 20, 2012

Test Class Template for Apex Triggers

Having written a lot of test methods to validate trigger functionality, I've developed a general template for writing trigger-related test methods that hopefully encompasses all of the steps needed. I believe that there must be a generic template that can be applied to 99% of the trigger test cases out there, and I hope this is a good start in that direction.

@isTest
private class GenericTriggerTest {

    /**
     * Plain English description of what is being
     * tested and why.
     */
    public static testMethod insertSObjects() {

        // Stage the test data.

        // Set parameters and expectations.
        // Which records am I using?
        // What do I expect to change or see
        // at the end of the test?

        // Validate pre-conditions.
        // Impersonate another user
        // if appropriate.

        //System.runAs(null);
        System.assert(false, 'TODO');

        // Start the test.

        Test.startTest();

        // Execute test operations.

        // Stop the test.

        Test.stopTest();

        // Validate the results.

        System.assert(false, 'TODO');
    }   // static insertSObjects()

    /**
     * Plain English description of what is being
     * tested and why.
     */
    public static testMethod updateSObjects() {
        System.assert(false, 'TODO');
    }   // static updateSObjects()

    /**
     * Plain English description of what is being
     * tested and why.
     */
    public static testMethod deleteSObjects() {
        System.assert(false, 'TODO');
    }   // static deleteSObjects()
}   // private class GenericTriggerTest

Feedback on the template will be much appreciated.

Thursday, December 29, 2011

Last Modified Date Rounding to Whole Seconds

The DateTime class in Salesforce has precision down to the order of milliseconds, as implied by the getTime method which "returns the number of milliseconds since January 1, 1970, 00:00:00 GMT represented by this DateTime object." Since the Last Modified Date field is a Date/Time field, one would assume that the Last Modified Date includes the millisecond value when stamping a record, right? Alas, this is not the case.

A video demonstrating the behavior: http://www.youtube.com/watch?v=IyRd1woiS24

It seems that Salesforce only includes the year, month, day, hour, minute and second when stamping the Last Modified Date. The millisecond value is simply zeroed out without any rounding. So, if a record was actually modified at 12/29/2011 12:31:20.578, Salesforce will stamp the record as being modified at 12/29/2011 12:31:20.000.

Okay, so there's a tiny discrepancy. I mean, we're talking tiny differences here. The million-dollar question: Why do I care?

I care because this little quirk caused my unit test to fail over 80% of the time due to the fact that comparing the Last Modified Date to DateTime.now() was producing unexpected results. For example:
  • At the beginning of the test method, DateTime.now() returned 12/29/2011 4:00:01.500.
  • At the end of the test method, the updated record's Last Modified Date shows 12/29/2011 4:00:01.000.
  • System.assert(record.LastModifiedDate >= testStartDateTime) fails unexpectedly and inconsistently.

The oddity with Last Modified Date is not an impossible problem to work around, but should I really be working around it? What does this mean for test-driven development that Apex is supposed to enable?

Thursday, November 17, 2011

Revolutionizing Unit Tests in Salesforce with Public Test Classes

One of the coolest features in Winter '12 for any organization that uses Apex has to be public test classes.

Why? One main reason: Public test classes combined with a tool like HardBoil will revolutionize unit testing in Salesforce!

Imagine a world where functional users (yes, functional users!), not developers, actually setup all of the unit tests through an interactive process that...
  • Saves developers countless hours of writing boilerplate code.
  • Drastically reduces human error in staging test data, checking pre-conditions and asserting post-conditions.
  • Produces clean, self-documenting and easy-to-read test code.
  • And trains functional users to learn the data structures and respect data quality, all at the same time!

Here's the immediately achievable concept: Create a single, public test class (perhaps using HardBoil) called something like EnterpriseTestDb. Then, all one has to do is start every test method by instantiating EnterpriseTestDb as follows:
// Stage test data.

EnterpriseTestDb db = new EnterpriseTestDb();

// Set test parameters.

Account largeAccount =
        db.getAccountByName('Acme Corporation');

Contact mainContact =
        db.getContactByName('John Doe');

...

The best parts about all of this, again, is that...
  • Not a single second of developer time was needed to create potentially hundreds of test records that can support every single unit test in the entire org!
  • Functional users learned the data structure by setting up all of the test data for their developers!

And the long-term concept? Automatically generating test methods already setup to check pre-conditions and assert post-conditions, thereby allowing developers to simply fill in the code in each test method to move from the pre-condition to the post-condition.

In short, I can't wait for this new world to arrive.