48
10 Principles of Apex Testing May 21 st , 2015

10 principles of apex testing

Embed Size (px)

Citation preview

10 Principles of Apex TestingMay 21st, 2015

#forcewebinar

Speakers

Kevin PoormanPrinciple Architect, EDL Consulting@Codefriar

#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 deliveringnew 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.comproducts, 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 toYouTube & the webinar recappage (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

Agenda

1. Why we do Testing2. 10 principles of Apex Testing

3. Questions and Answers

#forcewebinar

Why test? (when you have users)

#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 AssertsYou can write your own assert methods!@isTestPublic class customAssertionspublic class customAssertionException extends ExceptionPublic Boolean DuplicateAccount(Account a, Account b)

// … compare accountsif(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 TestsPublic class exampleCode Public Integer add(Integer one, Integer two)

return one + two;

#forcewebinar

Principle #3, Positive Tests@isTestprivate 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 TestsPublic 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@isTestprivate 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 TestsPublic class exampleCode Public class exampleCodeException

Public Integer getBankAccount(Account a)

return a.SuperSecretBankAccountNum__c;

#forcewebinar

Principle #5, User Tests Positive@isTestprivate 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@isTestprivate 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@isTestprivate 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 Test Calls a service

Returns ???

Traditional integration testing

#forcewebinar

Principle #8, MockingUnit 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@isTestPublic class exampleCode_TestsPublic 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@isTestpublic 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 successof our webinar programs. Thank you!

http://bit.ly/1FCyGiR

#forcewebinar

June 4, 2015

New Powerful API Enhancements for Summer ‘15

Upcoming Webinar

#forcewebinar

New York CityJune 16-­18, 2015

Join us in the Developer ZoneSalesforce World Tour

Register here: http://sfdc.co/XXXX

#forcewebinar

Q & A

Survey Link: http://bit.ly/1FCyGiR

Kevin PoormanPrinciple Architect, EDL Consulting@Codefriar

Thank You