Teach Me Salesforce

A community approach to learning salesforce.com

Author Archive

How To Write A Trigger Test

with 3 comments

One of the most often asked questions is “how do I test a trigger I have written”. This normally stems from the misunderstanding of how triggers run and what they actually do. A trigger is a piece of code that is defined to run either “before” or “after” a particular action is performed upon a record, namely “insert”, “update”, “undelete” or “delete”.

In the definition of your trigger you will know what context the trigger is occurring in (for example “after insert”) and you will have an understanding of the functionality this trigger will be performing. To test a trigger you must create an apex class which acts upon the record in the desired way (e.g. inserting a record) so that the trigger code will then get executed.

The example trigger shown below is a before trigger on a test object we have called TestObject__c with two text fields (Field1__c and Field2__c) and a Name field. When a record of this object type is sent to be inserted, before the insert occurs, our trigger runs and checks to see whether or not Field2__c is null (i.e. has been set) and if it has been set it then sets Field1__c to have this same value (trivial yes, but hopefully illustrative).


trigger TestObjectTrigger on TestObject__c (before insert)
{
for(TestObject__c obj : trigger.new)
{
obj.Field1__c = obj.Field2__c == null ? obj.Field2__c : null;
}
}

So we know what this trigger is doing, but what do we have to do to test it? At the highest level we want to insert a record and check that the trigger behaves as expected. So if we set a value for Field2__c then Field1__c will also get that value. What if we don’t set a value? Then we expect Field1__c to be null, so we need to test for that as well. Finally, when testing triggers we should attempt to do some volume testing as triggers are where we can easiest hit governor limits through looping etc (I know the limits are now increased, but good practice is a still good practice). So we will also include a test to insert 100 records and check they act as expected.

You will see in the code below that I have three private static methods in my test class to manage the insertion of the records. I recommend doing it this way for a number of reasons:

  1. You will have cleaner and better structured code
  2. You will reduce the number of places where bugs can be
  3. Your tests will be more consistent and easier to update and maintain
  4. You can easily add extra tests
  5. You can create very exact specifications for your tests easily and also remove a lot of data dependency problems

What do I mean by removing data dependency problems? If you are writing a trigger on a standard SObject (e.g. Account) or for a product that will be upgraded, then your tests will run against orgs where data of that type exists. Having very clear and structured data setup methods allows you to minimise the chance of someone already having records like those you are going to be considering (you will notice I use PBTest to help keep mine unique as it is an unlikely name to be given to an object and so I am unlikely to mistakenly retrieve the wrong object).

@isTest
private class TestObjectTriggerTest
{

static TestMethod void Test0_TestInsertWithValue()
{
string test0Value = ‘PBTest 0’;
insertTestObjectWithField2Value(test0Value);

TestObject__c testObj = [Select Name, Field1__c, Field2__c from TestObject__c where Name = :test0Value];

System.assertNotEquals(testObj, null, ‘Test 0 object was null and not inserted correctly’);

System.assertEquals(testObj.Field1__c, testObj.Field2__c, ‘Field1 and Field2 not equals in test 0’);
}

static TestMethod void Test1_TestInsertWithoutValue()
{
insertTestObject();

TestObject__c testObj = [Select Name, Field1__c, Field2__c from TestObject__c where Name = ‘PBTestValue’];

System.assertNotEquals(testObj, null, ‘Test 1 object was null and not inserted correctly’);

System.assertEquals(testObj.Field1__c, testObj.Field2__c, ‘Field1 and Field2 not equals in test 0’);
}

static TestMethod void Test2_TestMultipleValues()
{
List values = new List();
for(integer i=0; i<100; i++)
{
values.add(‘PBTest ‘ + i);
}

insertTestObjectsWithField2Values(values);

List objects = [Select Name, Field1__c, Field2__c from TestObject__c where Name in :values Order By Name];

for(TestObject__c obj : objects)
{
System.assertEquals(obj.Field1__c, obj.Field2__c, ‘In test 3, test object ‘ + obj.Name + ‘ Field 1 and Field 2 differ’);
}
}

private static void insertTestObject()
{
TestObject__c obj = new TestObject__c();
obj.Name = ‘PBTestValue’;
insert obj;
}

private static void insertTestObjectWithField2Value(String field2Value)
{
TestObject__c obj = new TestObject__c();
obj.Name = field2Value;
obj.Field2__c = field2Value;
insert obj;
}

private static void insertTestObjectsWithField2Values(List fieldValues)
{
integer i = 0;
List objs = new List();
for(string value : fieldValues)
{
TestObject__c obj = new TestObject__c();
obj.Field2__c = value;
obj.Name = ‘PBTest’ + i;
objs.add(obj);
i++;
}

insert objs;
}
}

The code is self-explanatory and should give enough insight as to how a trigger is tested properly. It runs and passes at 100%.

A final note is that trigger testing is extremely important, not only because Salesforce mandate it but because trigger code is some of the most used code you have in your system. As a system grows and its rules become more complex with multiple records being created automatically of the back of the creation of other records, your trigger code will be used extensively and therefore thorough testing (including volumes) is a must.

Advertisements

Written by pbattisson

May 7, 2011 at 7:17 am