0% found this document useful (0 votes)
95 views33 pages

The Principles of Apex Testing

The document summarizes key principles for testing Apex code. It discusses: 1) Writing tests provides assurance of functionality, reduces costs of changes, helps identify bugs, and documents expected behavior. 2) Successful unit tests in Apex follow a recipe: create test data, startTest() to reset limits, execute the unit of code, stopTest() and make assertions. 3) Tests should use assertions to validate outputs and include multiple assertions. Custom assertions can also be written. Positive and negative tests are important to validate expected and unexpected behaviors.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PPTX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
95 views33 pages

The Principles of Apex Testing

The document summarizes key principles for testing Apex code. It discusses: 1) Writing tests provides assurance of functionality, reduces costs of changes, helps identify bugs, and documents expected behavior. 2) Successful unit tests in Apex follow a recipe: create test data, startTest() to reset limits, execute the unit of code, stopTest() and make assertions. 3) Tests should use assertions to validate outputs and include multiple assertions. Custom assertions can also be written. Positive and negative tests are important to validate expected and unexpected behaviors.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PPTX, PDF, TXT or read online on Scribd
You are on page 1/ 33

The principles of Apex Testing

Agenda:

1. Why we’re here


2. Let's talk about why we write tests
3.The most important principles of testing
Apex Code
4.A brief note on Mocking (Not the making fun
of things kind)
*I found this comment in an org once.
In a “test” class full of carefully
crafted additions.
i++;
i+
+;
i++;

Syst
em.a
sser
t(i
=
1000
);
*Let's talk about
why we test.
1. Tests provide assurance of
functionality
2. Tests reduce cost of change
3. Tests help identify engineering and
architectural bugs
4. Tests help document expected
behavior
5. Tests + Code = less likely to
*Principle #1 also known
A recipe for successful unit tests in Apex code as: the general idea
Test Method

Create Test Data

StartTest()

Execute Your Unit of Code

StopTest()

Assertions
*Principle #2, Use @isTest And
@TestSetup
*Principle #3, Use Asserts
A test without Assert methods isn’t a test, it’s a
liability. Three Assert methods built-in
• System.Assert(boolean-expression, ‘friendly
message’)
• System.AssertEquals(expect, actual, ‘friendly
message’)
•System.AssertNotEquals(expected, actual, ‘friendly message)
Every test method should include at least one assertion.
Good test methods include more than one.
The most robust, and helpful test methods include two sets of
asserts.
*Principle #3, Use Asserts
Top Tester Top Tip: You can write your own assert methods!
@isTest
public class customAssertions{
public class customAssertionException extends exception{}
public Boolean AssertDuplicateAccount(Account a, Account b){
// … compare accounts
if(duplicate != true) {
Throw new customAssertionException(‘whoa, it’s not the
same’);
}
return true; // Return true, without exception when
assertion is true.
}
}
*Principle #4, use startTest and
Start (then) Stop, Collaborate and Listen stopTest
Test.startTest() and Test.stopTest() help facilitate testing.
Isolates your code from the proper setup of the test(s)
startTest() resets DML, CPU Time and other governor limits, ensuring any limits you hit come
from your tested code!
stopTest() forces asynchronous code to complete.

All of the code before this method should be used to initialize variables, populate data structures, and so
on, allowing you to set up everything you need to run your test. Any code that executes after the call to
startTest and before stopTest is assigned a new set of governor limits.
*Principle #5 How to
test: Positive Tests Given
Valid

Input

Execute
d
I believe you can do it! Code

You should write ‘Positive Tests’.


Should
Positive tests prove the expected behavior, which is to say they
prove it does what you think it does Return

Lets talk about multiple expected behaviors, (what’s that


smell?) Expecte
Use Assertions d
Not just happy path testing to Output
prove
*Principle #4, Positive Tests

Public class exampleCode {


Public Integer add(Integer one, Integer two)
{ return one + two;
}
}
*Principle #4, Positive Tests
private class exampleCode_Tests {
@isTest static void test_Add_Postive()
{ exampleCode drWho = new
exampleCode(); Test.startTest();
Integer testValue = drWho.add(5,7);
Test.stopTest();
System.assertEquals(12, testValue,
‘Expected 5+7 to equal
12’);
}
*Principle #5, Negative Tests
Boolean
didCatch = Try {
false; It’s not you, it’s the *other drivers out there* that I
don’t trust.
Execute Negative tests prove that your code properly
Method handles exceptions and errors.
w/ Bad
Input The pattern works by calling method within a
try/catch block in the test. Catch only the
} Catch
expected type of exception in the catch block
() {
Less intuitive but more powerful!
At the very least, negatively test methods that
System.asser utilize user data
didCatc
t (didCatch)
h
= true;
*Principle #5, Negative Tests
Public class exampleCode {
Public class exampleCodeException{}
Public Static Integer division(Integer one, Integer two){
if(two == 0) {
Throw new exampleCodeException(‘Dividing by zero makes
kittens cry’);
}
return one / two;
}
}
*Principle #5, Negative Tests
private class exampleCode_Tests {
@isTest static void test_Divide_Negative() {
Boolean didCatchProperException = false;
Test.startTest(); Kittens are crying.
Try { Bad Data. No
donut.
exampleCode.divide(1, 0);
} catch (exampleCodeException AwesomeException){
didCatchProperException = true;
}
Test.stopTest();
System.assert(didCatchProperException,
‘Properly caught custom
Exception’);
*Principle #6, User Tests
Because really, do we want to give the HR team access to Products and
Opportunities?
User based tests prove your security model
User Should have
works like
Test with you of
Users think it does.Roles / Profiles
different Role 1 access
and Permission sets!
The pattern works like this: Create a user with User
a given profile. As needed assign permission NO access
Role 2
sets. Test both positive and negative users.

User w/ No Access
Perm before Perm
Set Set applied

User
w/o
No Acces
Perm
Set
*Principle #6, User Tests

Public class exampleCode {


Public class exampleCodeException{}
Public Integer getBankAccount(Account a){
return a.SuperSekr3tBankAccountNum

c;
}
}
*Principle #6, Positive User Tests
private class exampleCode_Tests {
@isTest static void test_getBankAccount_Positive()
{ exampleCode drWho = new exampleCode();
User u =
AwesomeTestLib.getUserWithProfile(‘DoctorProfile’
);
Account a = (Account)TestFactory.createSObject(new Account());
Integer result;
System.runAs(u)
{ Test.startTest
();
result =
drWho.getBankAc
count(a);
Test.stopTest();
*Principle #6, Negative User Tests
private class exampleCode_Tests {
@isTest static void test_getBankAccount_UberForNope()
{ exampleCode Dalek = new exampleCode();
User u =
AwesomeTestLib.getUserWithProfile(‘DalekProfile’);
Account a = (Account)TestFactory.createSObject(new Account());
Integer result;
System.runAs(u)
{ Test.startTest
();
result =
Dalek.getBankAc
count(a);
Test.stopTest();
}
*Principle #7, Testing with Perm Sets
private class exampleCode_Tests {
@isTest static void test_getBankAccount_W_PermSet()
{ exampleCode ClaraOswald= new exampleCode();
User u = AwesomeTestLib.getUserWithProfile(‘Standard
User’);
UtilityClass.AssignUserToPermissionSet(u, ‘Companion’);
Account a = (Account)TestFactory.createSObject(new Account());
Boolean result;
System.runAs(u){
Test.startTest();
result = ClaraOswald.canAccessTardis(a);
Test.stopTest();
}
System.assertNotEquals(result, null,
‘Expected ClaraOswald who has Companion Permissions to have access to the
Tardis’);
*Principle #8, Use your own data

Because, someone will delete the account named “do not delete, used for testing”
Always build your own test data.
If you created the data, you can precisely assert against it.
Unless you have to, never use @isTest(seeAllData=true)
List of Acceptable Reasons to use @seeAllData = true.
*Principle #8, Use your own data

When is it appropriate to use @isTest(seeAllData=true)?


One good reason you may still need to use SeeAllData is for any functionality you have built
around Report records. Your tests do not have default access to them, but they cannot be
created.
Another instance where you may need it is Field History Tracking. If you have logic that
depends on History records, I believe you cannot get them without SeeAllData.
*Principle #8, Use your own data
Work smarter, not harder.
• TestFactory, An open source test data factory from Daniel Hoechst. The coolest thing since the iPad.

Found in:

http://bit.ly/1c5exnV
• With it you can say:
• Account a = (Account)TestFactory.createSObject(new Account());
• Opportunity o = (Opportunity)TestFactory.createSObject(new
Opportunity(AccountId = a.Id));
• Account[] aList = (Account[])TestFactory.createSObjectList(new
Account(), 200);
*Principle #8, Use your own data
Examples:
*Principle #8, Use your own data
Examples:
*Principle #8, Use your own data
Loading Test Data
Using the Test.loadData method, you can populate data in your test methods without having to
write many lines of code.
Follow these steps:
-Add the data in a .csv file.
-Create a static resource for this file.
-Call Test.loadData within your test method and passing it the sObject type token and the
static resource name.

For example, for Account records and a static resource name of myResource, make the
following call:

List<sObject> ls = Test.loadData(Account.sObjectType, 'myResource');


*Principle #9, Mocking

Go ahead, mock me.


Integration vs Unit tests
• Integration tests test code in an execution context –
i.e. setup some data and execute the code within the
context.
• Unit tests focus on a single unit of code, not
necessarily a complete function.
Mocks allow us to write true unit tests by
‘mock’ objects.
• You get to setup the mock, and it’s responses.
*Principle #9, Mocking
The irritation of integration “unit”
tests

Ordinary Unit Test

Calls a service

Returns ???
*Principle #9, Mocking - Testing a single
HTTP callout
*Principle #9, Mocking Testing multiple
HTTP callouts
*Principle #9, Mocking Testing multiple
HTTP callouts
*Principle #10, What is Test.isRunningTest()method
The Test.isRunningTest() method is used to identify, if the piece of code being executed is invoked
from a Test class execution or from other artefacts such as a Trigger, Batch Job etc. Returns true if
the code being executed is invoked from a test class otherwise returns a false. Example:
1. To ensure the trigger doesn’t execute the batch if Test.IsRunningTest() is true, and then test the
batch class with it’s own test method.
2. Testing callouts – in our callout code we check to see if we‘re executing within a unit test context
by checking Test.isRunningTest() and instead of getting your callout response from an
HttpResponse.send() request, you return a pre-built test string instead.
If you have any questions, just call me

You might also like