#forcewebinar
Safe HarborSafe harbor statement under the Private Securities Litigation Reform Act of 1995:
This presentation may contain forward-looking statements that involve risks, uncertainties, and assumptions. If any such uncertainties materialize or if
any of the assumptions proves incorrect, the results of salesforce.com, inc. could differ materially from the results expressed or implied by the forward-
looking statements we make. All statements other than statements of historical fact could be deemed forward-looking, including any projections of
product or service availability, subscriber growth, earnings, revenues, or other financial items and any statements regarding strategies or plans of
management for future operations, statements of belief, any statements concerning new, planned, or upgraded services or technology developments
and customer contracts or use of our services.
The risks and uncertainties referred to above include – but are not limited to – risks associated with developing and delivering new functionality for our
service, new products and services, our new business model, our past operating losses, possible fluctuations in our operating results and rate of
growth, interruptions or delays in our Web hosting, breach of our security measures, the outcome of any litigation, risks associated with completed and
any possible mergers and acquisitions, the immature market in which we operate, our relatively limited operating history, our ability to expand, retain,
and motivate our employees and manage our growth, new releases of our service and successful customer deployment, our limited history reselling
non-salesforce.com products, and utilization and selling to larger enterprise customers. Further information on potential factors that could affect the
financial results of salesforce.com, inc. is included in our annual report on Form 10-K for the most recent fiscal year and in our quarterly report on
Form 10-Q for the most recent fiscal quarter. These documents and others containing important disclosures are available on the SEC Filings section of
the Investor Information section of our Web site.
Any unreleased services or features referenced in this or other presentations, press releases or public statements are not currently available and may
not be delivered on time or at all. Customers who purchase our services should make the purchase decisions based upon features that are currently
available. Salesforce.com, inc. assumes no obligation and does not intend to update these forward-looking statements.
#forcewebinar
Go Social!
Salesforce Developers
+Salesforce Developers
Salesforce Developers
Salesforce Developers The video will be posted to
YouTube & the webinar recap
page (same URL as registration).
This webinar is being recorded!
@salesforcedevs / #forcewebinar
So make sure to
leave comments
on YouTube
#forcewebinar
▪ Don’t wait until the end to ask your question!
– Technical support will answer questions starting now.
▪ Respect Q&A etiquette
– Please don’t repeat questions. The support team is working
their way down the queue.
▪ Stick around for live Q&A at the end
– Speakers will tackle more questions at the end, time-
allowing. If no one asks questions, Kevin will.
▪ Head to Developer Forums
– More questions? Visit developer.salesforce.com/forums
Have Questions?
#forcewebinar
Why we test?
Tests provide assurance of functionality
Tests reduce cost of change
Tests encourage modular, reusable code
Tests help identify engineering and architectural bugs
Tests help document expected behavior
Tests + Code = less likely to produce bugs
#forcewebinar
Principle #1, Use Asserts
A test without Assert methods isn’t a test, it’s code
execution
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
#forcewebinar
Principle #1, Use Asserts
You can write your own assert methods!
@isTest
Public class customAssertions{
public class customAssertionException extends Exception{}
Public Boolean DuplicateAccount(Account a, Account b){
// … compare accounts
if(duplicate != true) {
Throw new customAssertionException(‘whoa, it’s not the
same’);
}
return true;
}
}
#forcewebinar
Principle #2, use startTest and stopTest
Test.startTest() and Test.stopTest() help facilitate
testing.
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.
#forcewebinar
Principle #2, use startTest and stopTest
General pattern is to
– Create your test data
– Start the test
– Use that test data within your tested method
– End the Test
– Assert your code works as expected
#forcewebinar
Principle #3, Positive Tests
Write ‘Positive Tests’
Positive tests test the expected behavior
Lets talk about multiple expected behaviors
Not just happy path testing
#forcewebinar
Principle #3, Positive Tests
Public class exampleCode {
Public Integer add(Integer one, Integer two){
return one + two;
}
}
#forcewebinar
Principle #3, Positive Tests
@isTest
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’);
}
#forcewebinar
Principle #4, Negative Tests
Negative tests prove that your code properly handles
exceptions and errors.
The general pattern is to call your method within a
try/catch block in the test. Since you expect an
exception you’ll catch it in the catch block
Less intuitive but more powerful!
#forcewebinar
Principle #4, Negative Tests
Public class exampleCode {
Public class exampleCodeException{}
Public Integer division(Integer one, Integer two){
if(two == 0) {
Throw new exampleCodeException(‘Dividing by zero makes kittens cry’);
}
return one / two;
}
}
#forcewebinar
Principle #4, Negative Tests@isTest
private class exampleCode_Tests {
@isTest static void test_Divide_Negative() {
exampleCode drWho = new exampleCode();
Boolean didCatchProperException = false;
Test.startTest();
Try {
drWho.divide(1, 0);
} catch (exampleCodeException AwesomeException){
didCatchProperException = true;
}
Test.stopTest();
System.assert(didCatchProperException,
‘Properly caught custom Exception’);
}
#forcewebinar
Principle #5, User Tests
User based tests prove your security model
Test with Users of different Roles / Profiles and
Permission sets!
The pattern works like this: Create a user with a given
profile. As needed assign permission sets. Test both
positive and negative users.
#forcewebinar
Principle #5, User Tests
Public class exampleCode {
Public class exampleCodeException{}
Public Integer getBankAccount(Account a){
return a.SuperSecretBankAccountNum__c;
}
}
#forcewebinar
Principle #5, User Tests Positive@isTest
private class exampleCode_Tests {
@isTest static void test_getBankAccount_Positive() {
exampleCode drWho = new exampleCode();
User u = AwesomeTestLib.getUserWithProfile(‘JediProfile’);
Account a = (Account)TestFactory.createSObject(new Account());
Integer result;
System.runAs(u){
Test.startTest();
result = drWho.getBankAccount(a);
Test.stopTest();
}
System.assertNotEquals(result, null,
‘Expected this user to have access to bank #’);
}
#forcewebinar
Principle #5, User Tests - Negative@isTest
private class exampleCode_Tests {
@isTest static void test_getBankAccount_UberForNope() {
exampleCode drWho = new exampleCode();
User u = AwesomeTestLib.getUserWithProfile(‘SithProfile’);
Account a = (Account)TestFactory.createSObject(new Account());
Integer result;
System.runAs(u){
Test.startTest();
result = drWho.getBankAccount(a);
Test.stopTest();
}
System.assertEquals(result, null,
‘Expected Sith lords to be blocked’);
}
#forcewebinar
Principle #5, User Tests – w/ Permission set@isTest
private class exampleCode_Tests {
@isTest static void test_getBankAccount_W_PermSet() {
exampleCode drWho = new exampleCode();
User u = AwesomeTestLib.getUserWithProfile(‘Standard User’);
UtilityClass.AssignUserToPermissionSet(u, ‘canReadBankAccount’);
Account a = (Account)TestFactory.createSObject(new Account());
Integer result;
System.runAs(u){
Test.startTest();
result = drWho.getBankAccount(a);
Test.stopTest();
}
System.assertNotEquals(result, null,
‘Expected user with canReadBankAccount to read BankAccount#’);
}
#forcewebinar
Principle #6, Use your own data
Always build your own test data.
Unless you have to, never use
@isTest(seeAllData=true)
Rember you can dynamically write assertions:
– AssertEquals(AccountICreated.foo__c, ResultAccount.foo__c,
‘the two accounts should be the same!’);
#forcewebinar
Principle #6, Use your own data
General pattern is to
– Create your test data
– Use that test data within your tested method
– Assert your code works as expected
#forcewebinar
Principle #6, Use your own data
Tools to make this faster:
– TestFactory, An open source test data factory from Daniel
Hoechst. Found at http://bit.ly/1c5exnV
– 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);
#forcewebinar
Principle #7, Use a domain specific test helper lib
Test Helpers facilitate faster test writing
Additionally make tests easier to read, by abstracting
out superfluous code.
Mark your test helper as @isTest to ensure it’s never
called by live code, and to ensure it’s not counted
against you in code coverage
#forcewebinar
Principle #7, Use a domain specific test helper lib
Candidates for Test Helper classes include:
– Creating a user object with a given permission set assigned
– Generating complex object trees:
• generateAccountWOppAndProducts()
– Anything you do more than once in a test suite
– Make them public static methods and use a naming convention
• generate* - generates an object
• get* - retrieves an object via SOQL
#forcewebinar
Principle #8, Mocking
Integration v. Unit tests
– Integration tests test code in an execution context – Ie 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 ‘mocking’ objects.
– You get to setup the mock, and it’s responses.
#forcewebinar
Principle #8, Mocking
Unit TestCalls a service
Returns ???
Traditional integration testing
#forcewebinar
Principle #8, Mocking
Unit testing with mocks
MockObj
Unit Test
Returns known result
Returns known result
#forcewebinar
Principle #8, Mocking
Use mocks to insert objects whenever that object is not
critical to the test.
– For instance, if you’re testing a method that populates an
Account with the results of a webservice, mock out the web
services’ result.
– This allows you to test just what that method does to the
account object, not it’s ability to talk to a web service
#forcewebinar
Principle #8, Mocking
Not just for webservices – Mock all services!
– Mock anything you have in your service layer
– Use interfaces and write the unit test with a mock
implementation
#forcewebinar
Principle #8, Mocking@isTest
Public class exampleCode_Tests{
Public Boolean MockExample(Account a, Account b){
fflib_apexMocks m = new ffLib_apexMocks();
myInterface mock = new MockMyService(m);
m.startStubbing();
m.when(mock.add(5,7)).thenReturn(12);
m.stopStubbing();
Test.startTest();
ExampleCode mockObj = new exampleCode(myAwesomeService);
Integer result = mockObj.add(5,7);
Test.stopTest();
System.assertEquals(12, result, ‘friendly message’);
}
}
#forcewebinar
Principle #8, Mocking Part 2
Mocking HTTP Responses
Allows you to test HTTP Callouts without making the
Callout.
Interface requires you to return an HTTP Response
object.
#forcewebinar
Principle #8, Mocking Part 2 – Use a factory
@isTest
public with sharing class HTTPMockCalloutFactory implements HttpCalloutMock {
HTTPMockCalloutFactory (Integer code, String status, String body, Map<String,
String> responseHeaders) {
// set class variables here.
}
public HTTPResponse respond(HTTPRequest req) {
HttpResponse res = new HttpResponse();
res.setStatusCode(this.code);
res.setStatus(this.status);
res.setBody(this.bodyAsString);
return res;
}
}
#forcewebinar
Principle #8, Mocking Part 2 – Use a factory
You can even extend your factory to return different
response based on a static class variable. Useful for
testing multiple callout scenarios.
– Write an additional constructor that accepts a list of json strings
that de-serialize into responses
#forcewebinar
Principle #9, Write for testing
Write small, tightly focused methods that play well with
others.
Compose advanced functionality by using your small
methods together
Write more-or-less unit tests with these focused
methods, and integration tests for customized logic.
#forcewebinar
Principle #9, Write for testing: guidelines
Keep your methods to no more than 20 lines.
Keep method arguments to a minimum – no more than
four.
Write your Visualforce controllers to use a single
wrapper object.
– Either mock this wrapper object, or write a Test Helper method
to construct it.
Use descriptive method names!
#forcewebinar
Principle #10, Use Continuous Integration!
Continuous Integration is the idea that every code-
change committed to your source repository triggers a
full run of the tests.
A number of tools are available for CI on the
Salesforce1 platform.
Travis.ci, Drone.io, Jenkins and Codeship are some
examples
#forcewebinar
Principle #10, Use Continuous Integration!
CI gives you insight to failing tests as soon as they’re
committed not when you try to deploy
Facilitates multiple developers working on the same
project in their own sandboxes / dev orgs
Keeps you aware of code coverage as development
occurs.
#forcewebinar
Useful tips
Don’t insert or query unless you have to. You can often
test with objects in memory!
Learn more about Mocking by watching Jesse Altman’s
(@JesseAltman) Excellent intro to mocking with Apex
mocks here: http://bit.ly/1HtXk2B
Write and use a standardized Logging library that wraps
log data in a highly visible header/footer
#forcewebinar
Survey
Your feedback is crucial to the success
of our webinar programs. Thank you!
http://bit.ly/1FCyGiR
#forcewebinar
Q & A
Survey Link: http://bit.ly/1FCyGiR
Kevin Poorman
Principle Architect, EDL
Consulting
@Codefriar