Skip to content

Instantly share code, notes, and snippets.

@dhoechst
Last active April 28, 2022 03:30
Show Gist options
  • Save dhoechst/aa31d49bd6a961fe6b77 to your computer and use it in GitHub Desktop.
Save dhoechst/aa31d49bd6a961fe6b77 to your computer and use it in GitHub Desktop.
Testing Best Practices and Examples

This Gist shows code examples for Apex Testing Best Practices. It relys on having the TestFactory in your org.

public with sharing class MyApexClass {
// This method will be used to demonstrate a positive test
public static String doSomethingAwesome() {
return doSomethingAwesome(false);
}
// This method will be used to demostrate how to test a thrown exception
public static String doSomethingAwesome(Boolean throwException) {
if (throwException) {
throw new MyApexClassException('Something bad happened');
}
return 'Awesome';
}
// This method will be used to demonstrate how to test database queries
public static Account queryAccount() {
return [SELECT Name FROM Account LIMIT 1];
}
// This annotation makes a normally private method visible to unit tests
@TestVisible
private static String privateAwesome() {
return 'Still Awesome';
}
public class MyApexClassException extends Exception {}
}
@isTest
private class MyApexClassTest {
// This test shows a postive path.
@isTest static void verifyAwesome() {
System.assertEquals('Awesome', MyApexClass.doSomethingAwesome(), 'The awesome method was not so awesome.');
}
// This test shows how to cause an exception to be thrown and catch it.
@isTest static void exceptAwesome() {
try {
MyApexClass.doSomethingAwesome(true);
} catch (MyApexClass.MyApexClassException e) {
return;
}
System.assert(false, 'A MyApexClassException was expected, but not thrown.');
}
// This test shows how to setup test data to be used in your methods.
@isTest static void queryAccountTest() {
Account a = (Account) TestFactory.createSObject(new Account());
insert a;
Test.startTest(); // Resets all limits (DML, SOQL, etc)
Account testAccount = MyApexClass.queryAccount();
Test.stopTest();
System.assertEquals(a.Name, testAccount.Name, 'The wrong account was returned.');
}
// This test is calling a private method decorated with @TestVisible
@isTest static void verifyPrivateAwesome() {
System.assertEquals('Still Awesome', MyApexClass.privateAwesome());
}
}
trigger DemoContactTrigger on Contact (before insert) {
// Bulk version
/*
List<Id> acctIds = new List<Id>();
for (Contact c : Trigger.New) {
if (c.AccountId != null) {
acctIds.add(c.AccountId);
}
}
Map<Id, Account> acctMap = new Map<Id, Account>([SELECT Id, Account_Email__c FROM Account where Id in :acctIds]);
for (Contact c : Trigger.New) {
if (c.Email == null && c.AccountId != null) {
c.Email = acctMap.get(c.AccountId).Account_Email__c;
}
}
*/
// Non bulk version
for (Contact c : Trigger.New) {
if (c.Email == null) {
//if (c.Email == null && c.AccountId != null) {
c.Email = [SELECT Account_Email__c FROM Account WHERE Id = :c.AccountId].Account_Email__c;
}
}
}
@isTest
private class DemoContactTriggerTest {
@isTest static void insertSingleContactNoEmail() {
Account a = (Account) TestFactory.createSObject(new Account(Account_Email__c = 'info@demo.com'));
insert a;
Contact c = (Contact) TestFactory.createSObject(new Contact(AccountId = a.Id));
Test.startTest();
insert c;
Test.stopTest();
Contact testContact = [SELECT Email from Contact where Id = :c.Id];
System.assertEquals('info@demo.com', testContact.Email, 'The contact email should have been changed to the account email.');
}
@isTest static void insertSingleContactWithEmail() {
Account a = (Account) TestFactory.createSObject(new Account(Account_Email__c = 'info@demo.com'));
insert a;
Contact c = (Contact) TestFactory.createSObject(new Contact(AccountId = a.Id, Email = 'something@demo.com'));
Test.startTest();
insert c;
Test.stopTest();
Contact testContact = [SELECT Email from Contact where Id = :c.Id];
System.assertEquals('something@demo.com', testContact.Email, 'The contact email should not have been changed.');
}
@isTest static void insertPrivateContact() {
Contact c = (Contact) TestFactory.createSObject(new Contact(Email = 'something@demo.com'));
Test.startTest();
insert c;
Test.stopTest();
Contact testContact = [SELECT Email from Contact where Id = :c.Id];
System.assertEquals('something@demo.com', testContact.Email, 'The contact email should not have been changed.');
}
@isTest static void insertAccountNoEmail() {
Account a = (Account) TestFactory.createSObject(new Account());
insert a;
Contact c = (Contact) TestFactory.createSObject(new Contact(AccountId = a.Id));
Test.startTest();
insert c;
Test.stopTest();
Contact testContact = [SELECT Email from Contact where Id = :c.Id];
System.assertEquals(null, testContact.Email, 'There shouldn\'t be an email on the contact.');
}
@isTest static void insertBulkContact() {
Account a = (Account) TestFactory.createSObject(new Account(Account_Email__c = 'info@demo.com'));
insert a;
List<Contact> testContacts = (List<Contact>) TestFactory.createSObjectList(new Contact(AccountId = a.Id), 200);
Test.startTest();
insert testContacts;
Test.stopTest();
for (Contact c : [SELECT Email FROM Contact WHERE Id in :testContacts]) {
System.assertEquals('info@demo.com', c.Email, 'The contact email should have been changed to the account email.');
}
}
}
public with sharing class CalloutClass {
public static String doCallout() {
Http h = new Http();
HttpRequest req = new HttpRequest();
req.setEndpoint('https://api.endpoint.com/something');
req.setMethod('GET');
HttpResponse res = h.send(req);
return res.getBody();
}
}
@isTest
global class MockHttpResponse implements HttpCalloutMock {
global HTTPResponse respond(HTTPRequest req) {
HttpResponse res = new HttpResponse();
res.setHeader('Content-Type', 'application/json');
res.setStatusCode(200);
res.setBody('A response');
return res;
}
}
@isTest
private class CalloutClassTest {
@isTest static void testCallOut() {
Account a = (Account) TestFactory.createSObject(new Account());
insert a;
// We need to use startTest() to avoid an uncommitted work pending exception
Test.startTest();
Test.setMock(HttpCalloutMock.class, new MockHttpResponse());
String response = CalloutClass.doCallout();
Test.stopTest();
System.assertEquals('A response', response);
}
}
public with sharing class DemoControllerExtension {
private final Account acct;
public DemoControllerExtension(ApexPages.StandardController stdController) {
this.acct = (Account)stdController.getRecord();
}
public String param {
get {
if (param == null) {
param = ApexPages.currentPage().getParameters().get('param');
}
return param;
}
set;
}
public PageReference doSomething() {
if (param == null) {
ApexPages.addMessage(new ApexPages.Message(ApexPages.Severity.ERROR, 'No param provided'));
}
return null;
}
}
<apex:page standardController="Account" extensions="DemoControllerExtension">
<apex:pageMessages />
<apex:form>
<apex:pageBlock>
<apex:pageBlockButtons>
<apex:commandButton action="{!doSomething}" value="Do Something" />
</apex:pageBlockButtons>
<apex:pageBlockSection columns="1">
<apex:outputField value="{!Account.Name}" />
<apex:pageBlockSectionItem>
<apex:outputLabel value="Parameter" />
<apex:outputText value="{!param}" />
</apex:pageBlockSectionItem>
</apex:pageBlockSection>
</apex:pageBlock>
</apex:form>
</apex:page>
@isTest
private class DemoControllerExtensionTest {
private static Account testAccount;
static {
testAccount = (Account) TestFactory.createSObject(new Account());
insert testAccount;
}
@isTest static void checkErrorNoParam() {
DemoControllerExtension testCtrl = new DemoControllerExtension(new ApexPages.StandardController(testAccount));
testCtrl.doSomething();
System.assert(!ApexPages.getMessages().isEmpty(), 'There should be an error displayed on the page that no parameter was given.');
}
@isTest static void checkParam() {
ApexPages.CurrentPage().getParameters().put('param', testAccount.name);
DemoControllerExtension testCtrl = new DemoControllerExtension(new ApexPages.StandardController(testAccount));
testCtrl.doSomething();
System.assertEquals(testAccount.name, testCtrl.param);
System.assert(ApexPages.getMessages().isEmpty(), 'There should be no errors displayed on the page.');
}
}
@isTest
private class RunAsTest {
@isTest static void mixedDml() {
Profile p = [select id from profile where name='Standard User'];
User u = new User(alias = 'standt', email='standarduser@testorg.com',
emailencodingkey='UTF-8', lastname='Testing',
languagelocalekey='en_US',
localesidkey='en_US', profileid = p.Id,
timezonesidkey='America/Los_Angeles',
username='standarduser3234234@testorg.com');
insert u;
Group g = new Group();
g.Name = 'Test Group';
g.DeveloperName = 'TestGroup';
insert g;
GroupMember gm = new GroupMember();
gm.GroupId = g.Id;
gm.UserOrGroupId = u.Id;
insert gm;
// If you don't use runAs here, you will get a mixed DML exception
System.runAs(u) {
Account a = new Account();
a.Name = 'Test Account';
insert a;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment