Apex Testing and Best Practices

3.086 Aufrufe

Veröffentlicht am

Apex Testing and Best practices presented in Boston Salesforce world tour

Veröffentlicht in: Internet
0 Kommentare
3 Gefällt mir
Statistik
Notizen
  • Als Erste(r) kommentieren

Keine Downloads
Aufrufe
Aufrufe insgesamt
3.086
Auf SlideShare
0
Aus Einbettungen
0
Anzahl an Einbettungen
17
Aktionen
Geteilt
0
Downloads
119
Kommentare
0
Gefällt mir
3
Einbettungen 0
Keine Einbettungen

Keine Notizen für die Folie
  • To test methods defined with the future annotation, call the class containing the method in a startTest(), stopTest() code block. All asynchronous calls made after the startTest method are collected by the system. When stopTest is executed, all asynchronous processes are run synchronously.

    The startTest method does not refresh the context of the test: it adds a context to your test. For example, if your class makes 98 SOQL queries before it calls startTest, and the first significant statement after startTest is a DML statement, the program can now make an additional 100 queries. Once stopTest is called, however, the program goes back into the original context, and can only make 2 additional SOQL queries before reaching the limit of 100.
  • runAs() does not validate CRUD or Field Level Security permissions.
  • https://www.salesforce.com/us/developer/docs/apexcode/Content/apex_classes_annotation_testvisible.htm
  • StaticResourceCalloutMock mock = new StaticResourceCalloutMock();
    mock.setStaticResource('myStaticResourceName');
    mock.setStatusCode(200);
    mock.setHeader('Content-Type', 'application/json');
     
    Actual code :
    public class CalloutStaticClass {
    public static HttpResponse getInfoFromExternalService(String endpoint) {
    HttpRequest req = new HttpRequest();
    req.setEndpoint(endpoint);
    req.setMethod('GET');
    Http h = new Http();
    HttpResponse res = h.send(req);
    return res;
    }
    }
     

    -------------------

    @isTest

    private class CalloutStaticClassTest {
    @isTest static void testCalloutWithStaticResources() {
    // Use StaticResourceCalloutMock built-in class to
    // specify fake response and include response body
    // in a static resource.
    StaticResourceCalloutMock mock = new StaticResourceCalloutMock();
    mock.setStaticResource('mockResponse');
    mock.setStatusCode(200);
    mock.setHeader('Content-Type', 'application/json');

    // Set the mock callout mode
    Test.setMock(HttpCalloutMock.class, mock);

    // Call the method that performs the callout
    HTTPResponse res = CalloutStaticClass.getInfoFromExternalService(
    'http://api.salesforce.com/foo/bar');

    // Verify response received contains values returned by
    // the mock response.
    // This is the content of the static resource.
    System.assertEquals('{"hah":"fooled you"}', res.getBody());
    System.assertEquals(200,res.getStatusCode());
    System.assertEquals('application/json', res.getHeader('Content-Type'));
    }
    }
     

    ----------- Final Test Methods ---------------
    @isTest

    private class CalloutStaticClassTest {
    @isTest static void testCalloutWithStaticResources() {
    // Use StaticResourceCalloutMock built-in class to
    // specify fake response and include response body
    // in a static resource.
    StaticResourceCalloutMock mock = new StaticResourceCalloutMock();
    mock.setStaticResource('mockResponse');
    mock.setStatusCode(200);
    mock.setHeader('Content-Type', 'application/json');

    // Set the mock callout mode
    Test.setMock(HttpCalloutMock.class, mock);

    // Call the method that performs the callout
    HTTPResponse res = CalloutStaticClass.getInfoFromExternalService(
    'http://api.salesforce.com/foo/bar');

    // Verify response received contains values returned by
    // the mock response.
    // This is the content of the static resource.
    System.assertEquals('{"hah":"fooled you"}', res.getBody());
    System.assertEquals(200,res.getStatusCode());
    System.assertEquals('application/json', res.getHeader('Content-Type'));
    }
    }
     

  • Apex Testing and Best Practices

    1. 1. Introduction to Apex Testing Salesforce World Tour Boston
    2. 2. Jitendra Zaa Force.com MVP @JitendraZaa http://JitendraZaa.com
    3. 3. • Why do we need unit test • Getting started with Apex test classes • Testing Visualforce Controller • Web services Testing • Testing Apex Callouts • Best Practices • Q&A Agenda
    4. 4. • Development of robust, error-free code • As Salesforce is multitenant platform, make sure none of governor limits are hitting • To deploy code on production, unit tests are required • Minimum 75% of test coverage is required • Code coverage = number of unique apex lines executed / total number of lines in trigger , classes • These excludes comments, test methods • Unit tests are critical part of Salesforce development as it ensures success • Provides automated regression testing framework to make sure bug free future development Why unit test
    5. 5. • Apex code that tests other Apex code • Annotate class with @isTest • Class methods (static) • Defined with testMethod keyword • Classes defined with @isTest annotation does not count against organization limit of 2MB of Apex code. How to write unit test
    6. 6. @isTest public class myClass { static testMethod void myTest() { // Add test method logic using System.assert(), System.assertEquals() // and System.assertNotEquals() here. } } Sample Code
    7. 7. • Used to test governor limits • To make sure all Asynchronous code executes when stoptest() method is called • When startTest() method is called, fresh governor limits are applied until stopTest() is executed • startTest() and stopTest() can be called only once in testMethod. Test.startTest() and Test.stopTest()
    8. 8. trigger OverwriteTestAccountDescriptions on Account (before insert) { for(Account a: Trigger.new){ if (a.Name.toLowerCase().contains('test')){ a.Description = 'This Account is probably left over from testing. It should probably be deleted.'; } } } Trigger to be tested Sample Code
    9. 9. static testMethod void verifyAccountDescriptionsWhereOverwritten(){ // Perform our data preparation. List<Account> accounts = new List<Account>{}; for(Integer i = 0; i < 200; i++){ Account a = new Account(Name = 'Test Account ' + i); accounts.add(a); } // Start the test, this changes governor limit context to // that of trigger rather than test. test.startTest(); Test method to test Trigger Sample Code
    10. 10. // Insert the Account records that cause the trigger to execute. insert accounts; // Stop the test, this changes limit context back to test from trigger. test.stopTest(); // Query the database for the newly inserted records. List<Account> insertedAccounts = [SELECT Name, Description FROM Account WHERE Id IN&nbsp;:accounts]; // Assert that the Description fields contains the proper value now. for(Account a&nbsp;: insertedAccounts){ System.assertEquals( 'This Account is probably left over from testing. It should probably be deleted.', a.Description); } } Sample Code (cont.)
    11. 11. • By default Apex code runs in system mode • Permission and record sharing are not taken into consideration • System.runAs() method helps to change test context to either existing or new user • System.runAs() can only be used in testMethods System.runAs()
    12. 12. public class TestRunAs { public static testMethod void testRunAs() { // This code runs as the system user 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='standarduser@testorg.com'); System.runAs(u) { // The following code runs as user 'u' System.debug('Current User: ' + UserInfo.getUserName()); System.debug('Current Profile: ' + UserInfo.getProfileId()); } // Run some code that checks record sharing } } Sample Code
    13. 13. • Use TestVisible annotation to allow Test methods to access private or protected members of another class • These members can be methods , member variables or inner classes @TestVisible
    14. 14. public class TestVisibleExample { // Private member variable @TestVisible private static Integer recordNumber = 1; // Private method @TestVisible private static void updateRecord(String name) { // Do something } } Actual code to Test Sample Code
    15. 15. @isTest private class TestVisibleExampleTest { @isTest static void test1() { // Access private variable annotated with TestVisible Integer i = TestVisibleExample.recordNumber; System.assertEquals(1, i); // Access private method annotated with TestVisible TestVisibleExample.updateRecord('RecordName'); // Perform some verification } } Test Method Sample Code
    16. 16. • Like all Apex classes and Triggers, Visualforce controllers also requires Test methods • Test methods can automate user interaction by setting query parameter or navigating to different pages Test Visualforce Controller
    17. 17. public static testMethod void testMyController() { //Use the PageReference Apex class to instantiate a page PageReference pageRef = Page.success; //In this case, the Visualforce page named 'success' is the starting point of this test method. Test.setCurrentPage(pageRef); //Instantiate and construct the controller class. Thecontroller controller = new Thecontroller(); //Example of calling an Action method. Same as calling any other Apex method. String nextPage = controller.save().getUrl(); //Check that the save() method returns the proper URL. System.assertEquals('/apex/failure?error=noParam', nextPage); } Sample Code
    18. 18. • Generated code from WSDL is saved as Apex class and therefore needs to be tested • By default test methods does not support Web service call outs • Apex provides the built-in WebServiceMock interface and the Test.setMock method that you can use to receive fake responses in a test method. • Instruct the Apex runtime to generate a fake response whenever WebServiceCallout.invoke is called. Testing Web Services
    19. 19. @isTest global class WebServiceMockImpl implements WebServiceMock { global void doInvoke( Object stub, Object request, Map<String, Object> response, String endpoint, String soapAction, String requestName, String responseNS, String responseName, String responseType) { docSample.EchoStringResponse_element respElement = new docSample.EchoStringResponse_element(); respElement.EchoStringResult = 'Mock response'; response.put('response_x', respElement); } } Sample Code
    20. 20. public class WebSvcCallout { public static String callEchoString(String input) { docSample.DocSamplePort sample = new docSample.DocSamplePort(); sample.endpoint_x = 'http://api.salesforce.com/foo/bar'; // This invokes the EchoString method in the generated class String echo = sample.EchoString(input); return echo; } } Actual code that calls Web service Sample Code
    21. 21. @isTest private class WebSvcCalloutTest { @isTest static void testEchoString() { // This causes a fake response to be generated Test.setMock(WebServiceMock.class, new WebServiceMockImpl()); // Call the method that invokes a callout String output = WebSvcCallout.callEchoString('Hello World!'); // Verify that a fake result is returned System.assertEquals('Mock response', output); } } Test class to test Web service response Sample Code
    22. 22. • Apex has ability to call external Web services like Amazon, Facebook or any other Web service. • Salesforce does not has any control over response of external Web services. • Apex callouts can be tested either using HttpCalloutMock interface or using Static Resources. • HttpCalloutMock Is used to generate fake HttpResponse for testing purpose. Testing Apex Callouts
    23. 23. @isTest global class MockHttpResponseGenerator implements HttpCalloutMock { // Implement this interface method global HTTPResponse respond(HTTPRequest req) { // Create a fake response HttpResponse res = new HttpResponse(); res.setHeader('Content-Type', 'application/json'); res.setBody('{"foo":"bar"}'); res.setStatusCode(200); return res; } } Implementing HttpCalloutMock interface Sample Code
    24. 24. public class CalloutClass { public static HttpResponse getInfoFromExternalService() { HttpRequest req = new HttpRequest(); req.setEndpoint('http://api.salesforce.com/foo/bar'); req.setMethod('GET'); Http h = new Http(); HttpResponse res = h.send(req); return res; } } Actual code to be tested Sample Code
    25. 25. @isTest private class CalloutClassTest { @isTest static void testCallout() { // Set mock callout class Test.setMock(HttpCalloutMock.class, new MockHttpResponseGenerator()); // This causes a fake response to be sent // from the class that implements HttpCalloutMock. HttpResponse res = CalloutClass.getInfoFromExternalService(); // Verify response received contains fake values String contentType = res.getHeader('Content-Type'); System.assert(contentType == 'application/json'); String actualValue = res.getBody(); String expectedValue = '{"foo":"bar"}'; System.assertEquals(actualValue, expectedValue); System.assertEquals(200, res.getStatusCode()); } } Complete Test methods Sample Code
    26. 26. • Test methods take no arguments, commit no data to the database, and cannot send any emails. • Strive for 100% code coverage. Do not focus on the 75% requirement. • Write portable test methods and do not hardcode any Id or do not rely on some existing data. • If possible don’t use seeAllData=true annotation • Use System.assert methods to prove that code behaves properly. • In the case of conditional logic (including ternary operators), execute each branch of code logic. • Use the runAs method to test your application in different user contexts. • Exercise bulk trigger functionality—use at least 20 records in your tests. Best Practices
    27. 27. • Using static resource to mock Apex callout response • Apex Test methods Best practices Other resources
    28. 28. Go though Apex Testing module of Trailhead and earn your badge Trailhead
    29. 29. Thank you

    ×