Salesforce Test Classes

(if you haven’t realized that most of my pictures are tongue-in-cheek, let it be know now…LOL)

For any of you that have come from previous Object-Oriented languages to APEX, you have undoubtedly taken on the mantle that is APEX programming with whatever learning curve you had to go through.  We all have come to one single unifying rally point – being grumpy with Unit Tests.

Let me be the first to say that I fully support the concept behind Salesforce requiring Unit Tests for their code – wholeheartedly.  Anything that can help support their uptime metrics and keeping users from calling me repeatedly to ask “when will the system be back up?” is A-OK on my list.

Salesforce has also done a pretty darned good job at providing the developer masses with neat tools to achieve  that magical minimum 75% coverage.  I’ll also be the first to admit that Unit Tests were definitely a brain-bender for me to fully understand how to do RIGHT.

In this blog post, I’m going to try and line out some of the major Unit Test tenets that I’ve learned of and been burned by – please feel free to comment/reply down below if you have any more to add or if I’m just totally off my rocker on anything here.

Item #1 – Comment Your Code!

Please, please, please….comment your code.  It doesn’t count against any limits and it only helps everyone in the long run.  I hope and wish everyone with the most stable and long-term job endeavors, but realistically people come and go.  You will move projects, responsibilities, even companies – and the code you leave behind is your legacy.  As a consultant, I swear one of my responsibilities is to be thrown under the bus when something goes wrong (hey, I’ll take it) but the less you shoot yourself in the foot, the better.

This applies for BOTH regular code (APEX and VF) as well as your Unit Test Classes.  Go out for the weekend, knock a few too many back, then come back Monday and try to read your code.  (please don’t write any…) Stumble a bit?  Add more comments after you sober up, then add more after that.  I’ve never cursed a developer’s name because they commented too much.  Honestly I don’t care if you can’t spell either.  =P

Item #2 – Consolidate and Reuse your Code!

This is another core design tenet from Object Oriented programming.  If you have to go to another class to “see how you created that”, that code should be in a public utility class so it’s just written once.  Nothing gets me worse than fixing code in one place, and then watching my code fail compilation because the previous developer copied and pasted it in ten other places.

Salesforce to the rescue!  As of Winter ’12, they now allow us to have public Test Classes.  Awesome to the max, like totally dude.

The first thing that comes to mind when wanting to create truly good test classes is that you should never test against your organization’s data.  (See Item #3!)  Prior to Winter ’12, that meant unfortunately copying and pasting a litany of script and DML statements in each of your test classes (subsequently violating the title of this section, but I digress…) and falling prey to update hell when a rogue admin goes and makes a field readonly at the FLS level.

Enter Public Test Classes.  My typical implementation is to create a standalone “@isTest public class” to house the creation of data.  Break it out if you want into multiple methods, or have it be one big one:

@isTest
public class SharedResources_UnitTest {

//////////////////////////////////
// Don't forget your comments!
// Get a header in here!
//////////////////////////////////

public static void createAccount(String strAccountName) {

Account a = new Account();
a.Name = strAccountName;
insert a;

}

}

After that – it’s easy enough just to call it from your regular Test Class:

@isTest
private class createContact_UnitTest {

//////////////////////////////////
// Don't forget your comments!
// Get a header in here!
//////////////////////////////////

static testMethod void testCreatingContact() {

// Create Account via Shared Unit Test Class
SharedResources_UnitTest.createAccount('Test Account');

// Test Creation via System.Assert!
Account acct = [SELECT Id FROM Account WHERE Name = 'Test Account' LIMIT 1];
System.Assert(acct != null, 'createContact_UnitTest.testCreatingContact FAIL: Account was not inserted properly!);

// Create Contact
Contact conNew = new Contact();
conNew.Firstname = 'PeeWee';
conNew.LastName = 'Herman';
conNew.AccountId = acct.Id;
insert conNew;

// Test Creation via System.Assert!
Contact conTest = [SELECT Id FROM Contact WHERE LastName = 'Herman' AND AccountId = :acct.Id LIMIT 1];
System.Assert(acct != null, 'createContact_UnitTest.testCreatingContact FAIL: Contact was not inserted properly!);

}

}

Item #3 – Never test against the Organization’s Data

Yeah, it sure seems easy enough – and it was actually the default to do so back before Spring ’12 to be honest.  Heck, I’ve even tested against the Organization’s data before I got burned on it one too many times.

I think it’s great that Salesforce made it the default that you can’t see Organizational data.  Just as much as you created the classes and triggers to manipulate data, you should create the data that feeds them.  To be honest, it is just easier that way if you think about it.  =)

Getting burned – you have just written your version of Mr. Holland’s Opus in code, and you just deployed it with 100% test coverage.  You say, “meh, no one will ever delete that big account out of the system”.

You just sealed your fate.  Tomorrow an intern will be given the task to realign the accounts.  Boink goes your data, but you have no idea yet.

Enter yourself two months down the road and you have to tweak your code for the National Sales Meeting in the morning.  “Deployment Failed”.  Now you’re stuck up all night either being snakey and undeleting / recreating that account (perpetuating the problem) – or rewriting your Unit Tests properly to create your own data.  Either way, fail = you.

Yeah, it’ll take a little more time upfront to physically write the code, but you’ll pay yourself back in spades.

Item #4 – Use System.Assert!

Yeah, at first blush I didn’t either.  “I have coverage, why would I screw around with that now?”  For development in your own / corporate org, honestly you don’t need to use it.  You should, but you don’t HAVE to.

Why you should:  System.Assert (and the siblings AssertEquals / AssertNotEquals) validate that what you are doing equals what it should be at that point in your code.  It provides a hard fail / break in your code so that if something does go awry, you know exactly where and why – so you don’t end up troubleshooting somewhere way down the line.

@isTest
private class demoSystemAssert_UnitTest {

//////////////////////////////////
// Don't forget your comments!
// Get a header in here!
//////////////////////////////////

static testMethod void testSystemAssert() {

// Declare variables
Boolean bolValueOne = true;
Boolean bolValueTwo = false;

// Test 1 - the values should NOT match
System.Assert(bolValueOne != bolValueTwo, 'demoSystemAssert_UnitTest.testSystemAssert 1 FAIL: The values are EQUAL!);

// Set bolValueTwo to true
bolValueTwo = true;

// Test 2 - the values SHOULD match
System.Assert(bolValueOne == bolValueTwo, 'demoSystemAssert_UnitTest.testSystemAssert 2 FAIL: The values are NOT equal!);

// Set bolValueTwo back to false
bolValueTwo = false;

// Test 3 - the values do NOT match, but we are testing that they DO match (this will fail the test)
System.Assert(bolValueOne == bolValueTwo, 'demoSystemAssert_UnitTest.testSystemAssert 3 FAIL: The values are EQUAL!);

}

}

Think of your recent Unit Test class – how many lines you have in there and having something fail…at the end…and then backtracking up your code to see what the heck isn’t calculating properly.  System.Assert to the rescue.

That’s a good start, anyone have other ideas?

Comment below…

Advertisements