SlideShare uma empresa Scribd logo
1 de 44
Baixar para ler offline
Enhanced Web Service Testing
​ Kirk Steffke
​ AppExchange Practice Lead
​ kirk@crmscience.com
​ @kirkevonphilly
​ 
A Better Mock Structure
•  Test Coverage Overview
•  Review of Native Testing Methods
•  WebServiceMock and HttpCalloutMock
Interfaces
•  StaticResourceCalloutMock
•  MultiStaticResourceCalloutMock
•  Sample Scenario
•  Better Mock Structure
•  Setup
•  Review
Agenda
​ During this session
Test Coverage Overview
The who, what, when, where, and why’s of creating coverage
•  Code we write…
•  …about the code we just wrote
•  Test classes
•  Independent of code being tested
•  One or more test methods
•  @isTest annotation
Apex Test Coverage
​ “What” with a Hint of “How”
Apex Test Coverage
​ A Bit More of “How”
Grandma’s Famous Recipe
1.  Write code to do
something
2.  Create test class
3.  Mark with @isTest
4.  Create test method
5.  Create test data
6.  Invoke code being
tested
7.  Assert (+ or -)
•  Code we write…
•  …about the code we just wrote
•  Test classes
•  Independent of code being tested
•  One or more test method
Apex Test Coverage
Now More “What”
•  You, me, everyone
•  Required
•  75%
•  Ongoing Development
•  Help catch regressions
•  Positive and negative assertions
Apex Test Coverage
​ “Who-ot” and “Why”
•  As you’re developing
•  Moving code from sandbox to production
•  Creating packages
Apex Test Coverage
​ When
Native Testing Strategies
The Tools that are Already in your Toolbox
•  Class w/ single method that makes a callout
Sample Scenario: Single Callout
​ Class Needing Coverage
Sample Scenario: Single Callout
​ Class Needing Coverage
​ Gist: https://gist.github.com/KirkSteffke/2ca4357c7e84eece9073
•  Method making callout needs coverage
•  Don’t want test methods to actually make callout!
•  Responses to be used for positive/negative tests
Sample Scenario: Testing Objective
​ What We Need to Test
•  Defined within test class
•  Returns single callout
response
•  WebServiceMock for WSDL
based SOAP callouts
•  HttpCalloutMock for testing
Http callouts
•  Defined by content of text
file in Static Resource
•  Returns response for a
single endpoint
•  Similar to
StaticResourceCalloutMock
•  Static Resource contains
response for multiple
endpoints
WebServiceMock and
HttpCalloutMock Interfaces
StaticResourceCalloutMock
MultiStaticResourceCalloutMo
ck
Documentation: bit.ly/df15mock3Documentation: bit.ly/df15mock1 Documentation: bit.ly/df15mock2
Options for Testing HTTP Callouts
​ Out-of-the-box Tools
•  Defined within test class
•  Returns single callout
response
•  WebServiceMock for WSDL
based SOAP callouts
•  HttpCalloutMock for testing
Http callouts
•  Defined by content of text
file in Static Resource
•  Returns response for a
single endpoint
•  Similar to
StaticResourceCalloutMock
•  Static Resource contains
response for multiple
endpoints
WebServiceMock and
HttpCalloutMock Interfaces
StaticResourceCalloutMock
MultiStaticResourceCalloutMo
ck
Documentation: bit.ly/df15mock3Documentation: bit.ly/df15mock1 Documentation: bit.ly/df15mock2
Options for Testing HTTP Callouts
​ Out-of-the-box Tools
•  Not “the” test, but is @test
•  Called by test class methods
•  Returns “mock” responses
•  Sets up header, body, and status code
HttpCalloutMock Interface
​ Part 1: Mock Responder Class
HttpCalloutMock Interface
​ Part 1: Mock Responder Class
​ Gist: https://gist.github.com/KirkSteffke/0d1f22c77b6d3a2f5599
•  Test class for class making callout (part 1)
•  Utilizes Mock Responder Class (part 2)
•  Respond from callout comes from responder class (part 2)
HttpCalloutMock Interface
​ Part 2: Test Coverage
HttpCalloutMock Interface
​ Part 2: Test Coverage
HttpCalloutMock Interface
​ Recap
•  Defined within test class
•  Returns single callout
response
•  WebServiceMock for WSDL
based SOAP callouts
•  HttpCalloutMock for testing
Http callouts
•  Defined by content of text
file in Static Resource
•  Returns response for a
single endpoint
•  Similar to
StaticResourceCalloutMock
•  Static Resource contains
response for multiple
endpoints
WebServiceMock and
HttpCalloutMock Interfaces
StaticResourceCalloutMock
MultiStaticResourceCalloutMo
ck
Documentation: bit.ly/df15mock3Documentation: bit.ly/df15mock1 Documentation: bit.ly/df15mock2
Options for Testing HTTP Callouts
​ Out-of-the-box Tools
StaticResourceCalloutMock
Part 1: The static resource
•  Only contains JSON text
•  Can’t be a zipped static resource w/ multiple files
•  mock.setStaticResource(‘Name of Zip’,’File in Zip’)
StaticResourceCalloutMock
​ Part 2: Test coverage
•  Slightly different from last example
•  No separate class; defined within coverage
•  StaticResourceCalloutMock object instead of class with HttpCalloutMock interface
StaticResourceCalloutMock
​ Part 2: Test coverage
•  Defined within test class
•  Returns single callout
response
•  WebServiceMock for WSDL
based SOAP callouts
•  HttpCalloutMock for testing
Http callouts
•  Defined by content of text
file in Static Resource
•  Returns response for a
single endpoint
•  Similar to
StaticResourceCalloutMock
•  Static Resource contains
response for multiple
endpoints
WebServiceMock and
HttpCalloutMock Interfaces
StaticResourceCalloutMock
MultiStaticResourceCalloutMo
ck
Documentation: bit.ly/df15mock3Documentation: bit.ly/df15mock1 Documentation: bit.ly/df15mock2
Options for Testing HTTP Callouts
​ Out-of-the-box Tools
•  Two methods making callouts
•  One method using both
MultiStaticResourceCalloutMock
Part 1: Modified Scenario
•  Similar to StaticResourceCalloutMock
•  Define multiple endpoints
•  Each has own Static Resource
•  Still no Zip file
MultiStaticResourceCalloutMock
Part 2: Test Coverage
Static Resource: Example3_bar1 Static Resource: Example3_bar2
MultiStaticResourceCalloutMock
Part 2: Test Coverage
1.  New MultiStaticResourceCalloutMock()
2.  Set endpoint based resources
3.  Set mock
4.  Invoke callouts
5.  Perform assertions
Complex Scenario
A hypothetical, but real-world model to help you digest
•  Batch job
•  Import of Contacts from remote system
•  Remote system has an API
•  Two endpoints
•  /api/ContactCount
•  /api/Contacts
Remote Import via Batch
Overview
•  /api/ContactCount
•  Returns # of Contact records to be imported
•  Result can change during span of batch execution
•  /api/Contacts
•  Returns x number of contacts
•  Paginated
•  Page=1 – returns 1st 200 records
•  Page=2 – returns 2nd 200 records
•  …and so on
Remote Import via Batch
Meet the Endpoints
1.  Batch is called
2.  Start() method
3.  Each execute() iteration performs 2 callouts
4.  1st checks total # of records available
5.  2nd imports records
6.  End of execute determines if more
records?
7.  Execute may run for many iterations
8.  If no more records or limits, finish()
9.  Restart cycle
10.  End
Remote Import via Batch
Batch Flow
Better Mock Structure
Using our tools to make better tools
Limitations
Working with Our Tools
•  HttpCalloutMock Interface and StaticResourceMock
•  Can only handle one endpoint
•  Single response
•  Single setup prior to invoking actual callouts
•  MultiStaticResourceCalloutMock
•  Handle multiple endpoints
•  Single response for each
•  Single setup prior to invoking actual callouts
Problems
Continued…
•  Challenge
•  Use one or more standard tool
•  Extend the usage
•  Create queue of expected responses per endpoint
•  Consider re-usability
•  MakeCallouts Method
•  Loops 10x
•  Builds string of results
•  ContactCount Method
•  Makes Callout
•  Contacts Method
•  Makes callout
•  Page Parameter
Building the Problem
Example4_CalloutClass.apxc
public class Example4_CalloutClass {
// Method to simulate all the callouts in our batch flow
public static string MakeCallouts() {
// Property to return
string results = '';
// Let's call each resource 10x and...
for (integer i = 0; i < 10; i++) {
// ...add to results string this Count's response's body
results += 'Count (' + i + '): ' + CalloutContactCount().getBody() + 'rn';
// ...add to results string this Contact response's body
results += 'Contacts (' + i + '): ' + CalloutContacts(i).getBody() + 'rn';
}
// Return concatenated string of results
return results;
•  ResponseMap
•  By method
•  By endpoint
•  List of responses
•  Respond
•  Verify request
•  Prepare response
•  Discard
•  Resp Class
Building the Solution
TestCalloutResponseGenerator.apxc
@isTest
global class TestCalloutResponseGenerator implements HttpCalloutMock {
// Property and getter (semi init'd) to pair method --> endpoint --> list of responses
private static map<string, map<string, list<resp>>> ResponseMap;
public static map<string, map<string, list<resp>>> getResponseMap() {
if (ResponseMap == null) {
ResponseMap = new map<string, map<string, list<resp>>>();
// For each setMethod() method type, pre-pop. w/ empty map
for (string method :new list<string>{'GET','PUT','POST','DELETE','HEAD','TRACE'})
ResponseMap.put(method, new map<string, list<resp>>());
}
return ResponseMap;
}
// Required respond() method for HttpCalloutMock
public HttpResponse Respond(HttpRequest req) {
•  Body (JSON)
•  Status (success)
•  StatusCode
•  Discard
Building the Solution
TestCalloutResponseGenerator.Resp
// Class to hold details of response from within test methods
public class Resp {
public string body { get; set; }
public string status { get; set; }
public integer statusCode { get; set; }
public boolean discard { get; set; }
public Resp(string body, string status, integer statusCode, boolean discard) {
this.body = body;
this.status = status;
this.statusCode = statusCode;
this.discard = discard;
}
}
•  ResponseMap
•  By method
•  By endpoint
•  List of responses
Building the Solution
TestCalloutResponseGenerator.getResponseMap()
// Property to pair method --> endpoint --> list of responses
private static map<string, map<string, list<resp>>> ResponseMap;
// Getter to return or prepare a semi init'd response map
public static map<string, map<string, list<resp>>> getResponseMap() {
if (ResponseMap == null) {
ResponseMap = new map<string, map<string, list<resp>>>();
// For each setMethod() method type, pre-pop. w/ empty map
for (string method :new list<string>{'GET','PUT','POST','DELETE','HEAD','TRACE'})
ResponseMap.put(method, new map<string, list<resp>>());
}
return ResponseMap;
}
•  Respond
•  Verify request
•  Prepare response
•  Discard
Building the Solution
TestCalloutResponseGenerator.Respond(HttpRequest req)
// Required respond() method for HttpCalloutMock
public HttpResponse Respond(HttpRequest req) {
// Property for returned response
HttpResponse res = new HttpResponse();
// Ensure HttpRequest is valid
if (req != null && !string.isBlank(req.getMethod()) && !string.isBlank(req.getEndPoint())) {
// Verify the Response map contains the req's method and endpoint
if (getResponseMap().containsKey(req.getMethod()) &&
getResponseMap().get(req.getMethod()).containsKey(req.getEndpoint())
) {
// Instantiate a list of the method/endpoint's response bodies
list<resp> respList =
getResponseMap().get(req.getMethod()).get(req.getEndpoint());
// If there's at least one, use it - otherwise, output an error
if (!respList.isEmpty()) {
•  Setup ResponseMap
•  Shortcut Explanation
•  Contacts
•  ContactCount
•  Discard
•  Set mock
•  Invoke Callout
Testing the Solution
Example4_TestCalloutClass.TestWithPattern()
@isTest
public class Example4_TestCalloutClass {
public static testMethod void TestWithPattern() {
/* The below is just a shortcut for the demo. Instead of this 10x (1 per page):
TestCalloutResponseGenerator.getResponseMap().get('GET').put(
'/api/Contacts?page=1',
new list<TestCalloutResponseGenerator.Resp> {
new TestCalloutResponseGenerator.Resp(
'{"Contacts":"data...page 1'"}',
'success',
200,
false
)
}
);
*/
// Temporary collection to hold looped results (for demo, we don't care about actual data,
Testing the Solution
Example4_TestCalloutClass.TestWithPattern()
// Temporary collection to hold looped results (for demo, we don't care about actual data, just proof of concept)
map<string, list<TestCalloutResponseGenerator.Resp>> pagedResponses =
new map<string, list<TestCalloutResponseGenerator.Resp>>();
// Create a dummy response for Contact callout for our "10" pages of contacts
for (integer i = 0; i < 10; i++) {
// Each loop = 1 page
pagedResponses.put('/api/Contacts?page=' + i, new list<TestCalloutResponseGenerator.Resp>{
new TestCalloutResponseGenerator.Resp(
'{"Contacts":"data...' + i + '"}',
'success',
200,
true)
});
}
// Add all of the contact responses to the response map
TestCalloutResponseGenerator.getResponseMap().put('GET', pagedResponses);
•  Setup ResponseMap
•  Shortcut Explanation
•  Contacts
•  ContactCount
•  Discard
•  Set mock
•  Invoke Callout
Testing the Solution
Example4_TestCalloutClass.TestWithPattern()
// Enable mock response
Test.setMock(HttpCalloutMock.class, new TestCalloutResponseGenerator());
// Invoke the callout method
string results = Example4_CalloutClass.MakeCallouts();
system.debug('Results: rnrn' + results);
Testing the Solution
TestCalloutClass
1.  Count or Contact callout
2.  # of loop iteration
3.  Count data 10, 12, 12, …
1.  Use 1st, discard
2.  Use 2nd, don’t discard
4.  Contact data increments
1.  Provided per page response
Thank you

Mais conteúdo relacionado

Mais procurados

Agile Testing Strategy
Agile Testing StrategyAgile Testing Strategy
Agile Testing Strategy
tharindakasun
 
Role Of Qa And Testing In Agile 1225221397167302 8
Role Of Qa And Testing In Agile 1225221397167302 8Role Of Qa And Testing In Agile 1225221397167302 8
Role Of Qa And Testing In Agile 1225221397167302 8
a34sharm
 
Software Testing Services
Software Testing ServicesSoftware Testing Services
Software Testing Services
Fuad Mak
 
Best practices quality assurance
Best practices   quality assuranceBest practices   quality assurance
Best practices quality assurance
Shakal Shukla
 

Mais procurados (20)

Fundamentals OF UAT
Fundamentals OF UATFundamentals OF UAT
Fundamentals OF UAT
 
Writing Test Cases 20110808
Writing Test Cases 20110808Writing Test Cases 20110808
Writing Test Cases 20110808
 
Sanity testing and smoke testing
Sanity testing and smoke testingSanity testing and smoke testing
Sanity testing and smoke testing
 
Test Automation Best Practices (with SOA test approach)
Test Automation Best Practices (with SOA test approach)Test Automation Best Practices (with SOA test approach)
Test Automation Best Practices (with SOA test approach)
 
API Test Automation Using Karate (Anil Kumar Moka)
API Test Automation Using Karate (Anil Kumar Moka)API Test Automation Using Karate (Anil Kumar Moka)
API Test Automation Using Karate (Anil Kumar Moka)
 
Agile Testing Strategy
Agile Testing StrategyAgile Testing Strategy
Agile Testing Strategy
 
Agile testing - Testing From Day 1
Agile testing - Testing From Day 1Agile testing - Testing From Day 1
Agile testing - Testing From Day 1
 
Best Practices for Testing in salesforce.com
Best Practices for Testing in salesforce.comBest Practices for Testing in salesforce.com
Best Practices for Testing in salesforce.com
 
Role Of Qa And Testing In Agile 1225221397167302 8
Role Of Qa And Testing In Agile 1225221397167302 8Role Of Qa And Testing In Agile 1225221397167302 8
Role Of Qa And Testing In Agile 1225221397167302 8
 
Software Testing Services
Software Testing ServicesSoftware Testing Services
Software Testing Services
 
Test Automation Framework with BDD and Cucumber
Test Automation Framework with BDD and CucumberTest Automation Framework with BDD and Cucumber
Test Automation Framework with BDD and Cucumber
 
The Future of QA at Atlassian
The Future of QA at AtlassianThe Future of QA at Atlassian
The Future of QA at Atlassian
 
Test automation
Test automationTest automation
Test automation
 
Software testing - basics
Software testing - basicsSoftware testing - basics
Software testing - basics
 
Performance testing presentation
Performance testing presentationPerformance testing presentation
Performance testing presentation
 
SDLC vs STLC
SDLC vs STLCSDLC vs STLC
SDLC vs STLC
 
Test plan
Test planTest plan
Test plan
 
Software testing
Software testingSoftware testing
Software testing
 
Best practices quality assurance
Best practices   quality assuranceBest practices   quality assurance
Best practices quality assurance
 
Performance Requirement Gathering
Performance Requirement GatheringPerformance Requirement Gathering
Performance Requirement Gathering
 

Semelhante a Enhanced Web Service Testing: A Better Mock Structure

Test in action – week 1
Test in action – week 1Test in action – week 1
Test in action – week 1
Yi-Huan Chan
 
Test in action week 2
Test in action   week 2Test in action   week 2
Test in action week 2
Yi-Huan Chan
 
Unit Testing in SharePoint 2010
Unit Testing in SharePoint 2010Unit Testing in SharePoint 2010
Unit Testing in SharePoint 2010
Chris Weldon
 
API-Testing-SOAPUI-1.pptx
API-Testing-SOAPUI-1.pptxAPI-Testing-SOAPUI-1.pptx
API-Testing-SOAPUI-1.pptx
amarnathdeo
 

Semelhante a Enhanced Web Service Testing: A Better Mock Structure (20)

Enhanced Web Service Testing: A Better Mock Structure
Enhanced Web Service Testing: A Better Mock StructureEnhanced Web Service Testing: A Better Mock Structure
Enhanced Web Service Testing: A Better Mock Structure
 
Developer testing 101: Become a Testing Fanatic
Developer testing 101: Become a Testing FanaticDeveloper testing 101: Become a Testing Fanatic
Developer testing 101: Become a Testing Fanatic
 
Apex Testing and Best Practices
Apex Testing and Best PracticesApex Testing and Best Practices
Apex Testing and Best Practices
 
Performance Test Driven Development with Oracle Coherence
Performance Test Driven Development with Oracle CoherencePerformance Test Driven Development with Oracle Coherence
Performance Test Driven Development with Oracle Coherence
 
Test in action – week 1
Test in action – week 1Test in action – week 1
Test in action – week 1
 
Android dev 3
Android dev 3Android dev 3
Android dev 3
 
Web Services Automated Testing via SoapUI Tool
Web Services Automated Testing via SoapUI ToolWeb Services Automated Testing via SoapUI Tool
Web Services Automated Testing via SoapUI Tool
 
Jdbc presentation
Jdbc presentationJdbc presentation
Jdbc presentation
 
More on Fitnesse and Continuous Integration (Silicon Valley code camp 2012)
More on Fitnesse and Continuous Integration (Silicon Valley code camp 2012)More on Fitnesse and Continuous Integration (Silicon Valley code camp 2012)
More on Fitnesse and Continuous Integration (Silicon Valley code camp 2012)
 
Test in action week 2
Test in action   week 2Test in action   week 2
Test in action week 2
 
SCWCD : Thread safe servlets : CHAP : 8
SCWCD : Thread safe servlets : CHAP : 8SCWCD : Thread safe servlets : CHAP : 8
SCWCD : Thread safe servlets : CHAP : 8
 
Tdd iPhone For Dummies
Tdd iPhone For DummiesTdd iPhone For Dummies
Tdd iPhone For Dummies
 
Unit testing with Spock Framework
Unit testing with Spock FrameworkUnit testing with Spock Framework
Unit testing with Spock Framework
 
Unit Testing in SharePoint 2010
Unit Testing in SharePoint 2010Unit Testing in SharePoint 2010
Unit Testing in SharePoint 2010
 
API-Testing-SOAPUI-1.pptx
API-Testing-SOAPUI-1.pptxAPI-Testing-SOAPUI-1.pptx
API-Testing-SOAPUI-1.pptx
 
Ajax Under The Hood
Ajax Under The HoodAjax Under The Hood
Ajax Under The Hood
 
Servlets
ServletsServlets
Servlets
 
The ASP.NET Web API for Beginners
The ASP.NET Web API for BeginnersThe ASP.NET Web API for Beginners
The ASP.NET Web API for Beginners
 
Unit Testng with PHP Unit - A Step by Step Training
Unit Testng with PHP Unit - A Step by Step TrainingUnit Testng with PHP Unit - A Step by Step Training
Unit Testng with PHP Unit - A Step by Step Training
 
Developer testing 201: When to Mock and When to Integrate
Developer testing 201: When to Mock and When to IntegrateDeveloper testing 201: When to Mock and When to Integrate
Developer testing 201: When to Mock and When to Integrate
 

Mais de Salesforce Developers

Mais de Salesforce Developers (20)

Sample Gallery: Reference Code and Best Practices for Salesforce Developers
Sample Gallery: Reference Code and Best Practices for Salesforce DevelopersSample Gallery: Reference Code and Best Practices for Salesforce Developers
Sample Gallery: Reference Code and Best Practices for Salesforce Developers
 
Maximizing Salesforce Lightning Experience and Lightning Component Performance
Maximizing Salesforce Lightning Experience and Lightning Component PerformanceMaximizing Salesforce Lightning Experience and Lightning Component Performance
Maximizing Salesforce Lightning Experience and Lightning Component Performance
 
Local development with Open Source Base Components
Local development with Open Source Base ComponentsLocal development with Open Source Base Components
Local development with Open Source Base Components
 
TrailheaDX India : Developer Highlights
TrailheaDX India : Developer HighlightsTrailheaDX India : Developer Highlights
TrailheaDX India : Developer Highlights
 
Why developers shouldn’t miss TrailheaDX India
Why developers shouldn’t miss TrailheaDX IndiaWhy developers shouldn’t miss TrailheaDX India
Why developers shouldn’t miss TrailheaDX India
 
CodeLive: Build Lightning Web Components faster with Local Development
CodeLive: Build Lightning Web Components faster with Local DevelopmentCodeLive: Build Lightning Web Components faster with Local Development
CodeLive: Build Lightning Web Components faster with Local Development
 
CodeLive: Converting Aura Components to Lightning Web Components
CodeLive: Converting Aura Components to Lightning Web ComponentsCodeLive: Converting Aura Components to Lightning Web Components
CodeLive: Converting Aura Components to Lightning Web Components
 
Enterprise-grade UI with open source Lightning Web Components
Enterprise-grade UI with open source Lightning Web ComponentsEnterprise-grade UI with open source Lightning Web Components
Enterprise-grade UI with open source Lightning Web Components
 
TrailheaDX and Summer '19: Developer Highlights
TrailheaDX and Summer '19: Developer HighlightsTrailheaDX and Summer '19: Developer Highlights
TrailheaDX and Summer '19: Developer Highlights
 
Live coding with LWC
Live coding with LWCLive coding with LWC
Live coding with LWC
 
Lightning web components - Episode 4 : Security and Testing
Lightning web components  - Episode 4 : Security and TestingLightning web components  - Episode 4 : Security and Testing
Lightning web components - Episode 4 : Security and Testing
 
LWC Episode 3- Component Communication and Aura Interoperability
LWC Episode 3- Component Communication and Aura InteroperabilityLWC Episode 3- Component Communication and Aura Interoperability
LWC Episode 3- Component Communication and Aura Interoperability
 
Lightning web components episode 2- work with salesforce data
Lightning web components   episode 2- work with salesforce dataLightning web components   episode 2- work with salesforce data
Lightning web components episode 2- work with salesforce data
 
Lightning web components - Episode 1 - An Introduction
Lightning web components - Episode 1 - An IntroductionLightning web components - Episode 1 - An Introduction
Lightning web components - Episode 1 - An Introduction
 
Migrating CPQ to Advanced Calculator and JSQCP
Migrating CPQ to Advanced Calculator and JSQCPMigrating CPQ to Advanced Calculator and JSQCP
Migrating CPQ to Advanced Calculator and JSQCP
 
Scale with Large Data Volumes and Big Objects in Salesforce
Scale with Large Data Volumes and Big Objects in SalesforceScale with Large Data Volumes and Big Objects in Salesforce
Scale with Large Data Volumes and Big Objects in Salesforce
 
Replicate Salesforce Data in Real Time with Change Data Capture
Replicate Salesforce Data in Real Time with Change Data CaptureReplicate Salesforce Data in Real Time with Change Data Capture
Replicate Salesforce Data in Real Time with Change Data Capture
 
Modern Development with Salesforce DX
Modern Development with Salesforce DXModern Development with Salesforce DX
Modern Development with Salesforce DX
 
Get Into Lightning Flow Development
Get Into Lightning Flow DevelopmentGet Into Lightning Flow Development
Get Into Lightning Flow Development
 
Integrate CMS Content Into Lightning Communities with CMS Connect
Integrate CMS Content Into Lightning Communities with CMS ConnectIntegrate CMS Content Into Lightning Communities with CMS Connect
Integrate CMS Content Into Lightning Communities with CMS Connect
 

Último

CNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of ServiceCNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of Service
giselly40
 

Último (20)

08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men
 
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
 
Exploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone ProcessorsExploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone Processors
 
Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)
 
2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...
 
Tech Trends Report 2024 Future Today Institute.pdf
Tech Trends Report 2024 Future Today Institute.pdfTech Trends Report 2024 Future Today Institute.pdf
Tech Trends Report 2024 Future Today Institute.pdf
 
Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024
 
Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...
 
presentation ICT roal in 21st century education
presentation ICT roal in 21st century educationpresentation ICT roal in 21st century education
presentation ICT roal in 21st century education
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected Worker
 
[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf
 
Handwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsHandwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed texts
 
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationFrom Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
 
What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?
 
Boost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivityBoost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivity
 
Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024
 
Scaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationScaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organization
 
How to convert PDF to text with Nanonets
How to convert PDF to text with NanonetsHow to convert PDF to text with Nanonets
How to convert PDF to text with Nanonets
 
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot TakeoffStrategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
 
CNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of ServiceCNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of Service
 

Enhanced Web Service Testing: A Better Mock Structure

  • 1. Enhanced Web Service Testing ​ Kirk Steffke ​ AppExchange Practice Lead ​ kirk@crmscience.com ​ @kirkevonphilly ​  A Better Mock Structure
  • 2. •  Test Coverage Overview •  Review of Native Testing Methods •  WebServiceMock and HttpCalloutMock Interfaces •  StaticResourceCalloutMock •  MultiStaticResourceCalloutMock •  Sample Scenario •  Better Mock Structure •  Setup •  Review Agenda ​ During this session
  • 3. Test Coverage Overview The who, what, when, where, and why’s of creating coverage
  • 4. •  Code we write… •  …about the code we just wrote •  Test classes •  Independent of code being tested •  One or more test methods •  @isTest annotation Apex Test Coverage ​ “What” with a Hint of “How”
  • 5. Apex Test Coverage ​ A Bit More of “How” Grandma’s Famous Recipe 1.  Write code to do something 2.  Create test class 3.  Mark with @isTest 4.  Create test method 5.  Create test data 6.  Invoke code being tested 7.  Assert (+ or -)
  • 6. •  Code we write… •  …about the code we just wrote •  Test classes •  Independent of code being tested •  One or more test method Apex Test Coverage Now More “What”
  • 7. •  You, me, everyone •  Required •  75% •  Ongoing Development •  Help catch regressions •  Positive and negative assertions Apex Test Coverage ​ “Who-ot” and “Why”
  • 8. •  As you’re developing •  Moving code from sandbox to production •  Creating packages Apex Test Coverage ​ When
  • 9. Native Testing Strategies The Tools that are Already in your Toolbox
  • 10. •  Class w/ single method that makes a callout Sample Scenario: Single Callout ​ Class Needing Coverage
  • 11. Sample Scenario: Single Callout ​ Class Needing Coverage ​ Gist: https://gist.github.com/KirkSteffke/2ca4357c7e84eece9073
  • 12. •  Method making callout needs coverage •  Don’t want test methods to actually make callout! •  Responses to be used for positive/negative tests Sample Scenario: Testing Objective ​ What We Need to Test
  • 13. •  Defined within test class •  Returns single callout response •  WebServiceMock for WSDL based SOAP callouts •  HttpCalloutMock for testing Http callouts •  Defined by content of text file in Static Resource •  Returns response for a single endpoint •  Similar to StaticResourceCalloutMock •  Static Resource contains response for multiple endpoints WebServiceMock and HttpCalloutMock Interfaces StaticResourceCalloutMock MultiStaticResourceCalloutMo ck Documentation: bit.ly/df15mock3Documentation: bit.ly/df15mock1 Documentation: bit.ly/df15mock2 Options for Testing HTTP Callouts ​ Out-of-the-box Tools
  • 14. •  Defined within test class •  Returns single callout response •  WebServiceMock for WSDL based SOAP callouts •  HttpCalloutMock for testing Http callouts •  Defined by content of text file in Static Resource •  Returns response for a single endpoint •  Similar to StaticResourceCalloutMock •  Static Resource contains response for multiple endpoints WebServiceMock and HttpCalloutMock Interfaces StaticResourceCalloutMock MultiStaticResourceCalloutMo ck Documentation: bit.ly/df15mock3Documentation: bit.ly/df15mock1 Documentation: bit.ly/df15mock2 Options for Testing HTTP Callouts ​ Out-of-the-box Tools
  • 15. •  Not “the” test, but is @test •  Called by test class methods •  Returns “mock” responses •  Sets up header, body, and status code HttpCalloutMock Interface ​ Part 1: Mock Responder Class
  • 16. HttpCalloutMock Interface ​ Part 1: Mock Responder Class ​ Gist: https://gist.github.com/KirkSteffke/0d1f22c77b6d3a2f5599
  • 17. •  Test class for class making callout (part 1) •  Utilizes Mock Responder Class (part 2) •  Respond from callout comes from responder class (part 2) HttpCalloutMock Interface ​ Part 2: Test Coverage
  • 20. •  Defined within test class •  Returns single callout response •  WebServiceMock for WSDL based SOAP callouts •  HttpCalloutMock for testing Http callouts •  Defined by content of text file in Static Resource •  Returns response for a single endpoint •  Similar to StaticResourceCalloutMock •  Static Resource contains response for multiple endpoints WebServiceMock and HttpCalloutMock Interfaces StaticResourceCalloutMock MultiStaticResourceCalloutMo ck Documentation: bit.ly/df15mock3Documentation: bit.ly/df15mock1 Documentation: bit.ly/df15mock2 Options for Testing HTTP Callouts ​ Out-of-the-box Tools
  • 21. StaticResourceCalloutMock Part 1: The static resource •  Only contains JSON text •  Can’t be a zipped static resource w/ multiple files •  mock.setStaticResource(‘Name of Zip’,’File in Zip’)
  • 22. StaticResourceCalloutMock ​ Part 2: Test coverage •  Slightly different from last example •  No separate class; defined within coverage •  StaticResourceCalloutMock object instead of class with HttpCalloutMock interface
  • 24. •  Defined within test class •  Returns single callout response •  WebServiceMock for WSDL based SOAP callouts •  HttpCalloutMock for testing Http callouts •  Defined by content of text file in Static Resource •  Returns response for a single endpoint •  Similar to StaticResourceCalloutMock •  Static Resource contains response for multiple endpoints WebServiceMock and HttpCalloutMock Interfaces StaticResourceCalloutMock MultiStaticResourceCalloutMo ck Documentation: bit.ly/df15mock3Documentation: bit.ly/df15mock1 Documentation: bit.ly/df15mock2 Options for Testing HTTP Callouts ​ Out-of-the-box Tools
  • 25. •  Two methods making callouts •  One method using both MultiStaticResourceCalloutMock Part 1: Modified Scenario
  • 26. •  Similar to StaticResourceCalloutMock •  Define multiple endpoints •  Each has own Static Resource •  Still no Zip file MultiStaticResourceCalloutMock Part 2: Test Coverage Static Resource: Example3_bar1 Static Resource: Example3_bar2
  • 27. MultiStaticResourceCalloutMock Part 2: Test Coverage 1.  New MultiStaticResourceCalloutMock() 2.  Set endpoint based resources 3.  Set mock 4.  Invoke callouts 5.  Perform assertions
  • 28. Complex Scenario A hypothetical, but real-world model to help you digest
  • 29. •  Batch job •  Import of Contacts from remote system •  Remote system has an API •  Two endpoints •  /api/ContactCount •  /api/Contacts Remote Import via Batch Overview
  • 30. •  /api/ContactCount •  Returns # of Contact records to be imported •  Result can change during span of batch execution •  /api/Contacts •  Returns x number of contacts •  Paginated •  Page=1 – returns 1st 200 records •  Page=2 – returns 2nd 200 records •  …and so on Remote Import via Batch Meet the Endpoints
  • 31. 1.  Batch is called 2.  Start() method 3.  Each execute() iteration performs 2 callouts 4.  1st checks total # of records available 5.  2nd imports records 6.  End of execute determines if more records? 7.  Execute may run for many iterations 8.  If no more records or limits, finish() 9.  Restart cycle 10.  End Remote Import via Batch Batch Flow
  • 32. Better Mock Structure Using our tools to make better tools
  • 33. Limitations Working with Our Tools •  HttpCalloutMock Interface and StaticResourceMock •  Can only handle one endpoint •  Single response •  Single setup prior to invoking actual callouts •  MultiStaticResourceCalloutMock •  Handle multiple endpoints •  Single response for each •  Single setup prior to invoking actual callouts
  • 34. Problems Continued… •  Challenge •  Use one or more standard tool •  Extend the usage •  Create queue of expected responses per endpoint •  Consider re-usability
  • 35. •  MakeCallouts Method •  Loops 10x •  Builds string of results •  ContactCount Method •  Makes Callout •  Contacts Method •  Makes callout •  Page Parameter Building the Problem Example4_CalloutClass.apxc public class Example4_CalloutClass { // Method to simulate all the callouts in our batch flow public static string MakeCallouts() { // Property to return string results = ''; // Let's call each resource 10x and... for (integer i = 0; i < 10; i++) { // ...add to results string this Count's response's body results += 'Count (' + i + '): ' + CalloutContactCount().getBody() + 'rn'; // ...add to results string this Contact response's body results += 'Contacts (' + i + '): ' + CalloutContacts(i).getBody() + 'rn'; } // Return concatenated string of results return results;
  • 36. •  ResponseMap •  By method •  By endpoint •  List of responses •  Respond •  Verify request •  Prepare response •  Discard •  Resp Class Building the Solution TestCalloutResponseGenerator.apxc @isTest global class TestCalloutResponseGenerator implements HttpCalloutMock { // Property and getter (semi init'd) to pair method --> endpoint --> list of responses private static map<string, map<string, list<resp>>> ResponseMap; public static map<string, map<string, list<resp>>> getResponseMap() { if (ResponseMap == null) { ResponseMap = new map<string, map<string, list<resp>>>(); // For each setMethod() method type, pre-pop. w/ empty map for (string method :new list<string>{'GET','PUT','POST','DELETE','HEAD','TRACE'}) ResponseMap.put(method, new map<string, list<resp>>()); } return ResponseMap; } // Required respond() method for HttpCalloutMock public HttpResponse Respond(HttpRequest req) {
  • 37. •  Body (JSON) •  Status (success) •  StatusCode •  Discard Building the Solution TestCalloutResponseGenerator.Resp // Class to hold details of response from within test methods public class Resp { public string body { get; set; } public string status { get; set; } public integer statusCode { get; set; } public boolean discard { get; set; } public Resp(string body, string status, integer statusCode, boolean discard) { this.body = body; this.status = status; this.statusCode = statusCode; this.discard = discard; } }
  • 38. •  ResponseMap •  By method •  By endpoint •  List of responses Building the Solution TestCalloutResponseGenerator.getResponseMap() // Property to pair method --> endpoint --> list of responses private static map<string, map<string, list<resp>>> ResponseMap; // Getter to return or prepare a semi init'd response map public static map<string, map<string, list<resp>>> getResponseMap() { if (ResponseMap == null) { ResponseMap = new map<string, map<string, list<resp>>>(); // For each setMethod() method type, pre-pop. w/ empty map for (string method :new list<string>{'GET','PUT','POST','DELETE','HEAD','TRACE'}) ResponseMap.put(method, new map<string, list<resp>>()); } return ResponseMap; }
  • 39. •  Respond •  Verify request •  Prepare response •  Discard Building the Solution TestCalloutResponseGenerator.Respond(HttpRequest req) // Required respond() method for HttpCalloutMock public HttpResponse Respond(HttpRequest req) { // Property for returned response HttpResponse res = new HttpResponse(); // Ensure HttpRequest is valid if (req != null && !string.isBlank(req.getMethod()) && !string.isBlank(req.getEndPoint())) { // Verify the Response map contains the req's method and endpoint if (getResponseMap().containsKey(req.getMethod()) && getResponseMap().get(req.getMethod()).containsKey(req.getEndpoint()) ) { // Instantiate a list of the method/endpoint's response bodies list<resp> respList = getResponseMap().get(req.getMethod()).get(req.getEndpoint()); // If there's at least one, use it - otherwise, output an error if (!respList.isEmpty()) {
  • 40. •  Setup ResponseMap •  Shortcut Explanation •  Contacts •  ContactCount •  Discard •  Set mock •  Invoke Callout Testing the Solution Example4_TestCalloutClass.TestWithPattern() @isTest public class Example4_TestCalloutClass { public static testMethod void TestWithPattern() { /* The below is just a shortcut for the demo. Instead of this 10x (1 per page): TestCalloutResponseGenerator.getResponseMap().get('GET').put( '/api/Contacts?page=1', new list<TestCalloutResponseGenerator.Resp> { new TestCalloutResponseGenerator.Resp( '{"Contacts":"data...page 1'"}', 'success', 200, false ) } ); */ // Temporary collection to hold looped results (for demo, we don't care about actual data,
  • 41. Testing the Solution Example4_TestCalloutClass.TestWithPattern() // Temporary collection to hold looped results (for demo, we don't care about actual data, just proof of concept) map<string, list<TestCalloutResponseGenerator.Resp>> pagedResponses = new map<string, list<TestCalloutResponseGenerator.Resp>>(); // Create a dummy response for Contact callout for our "10" pages of contacts for (integer i = 0; i < 10; i++) { // Each loop = 1 page pagedResponses.put('/api/Contacts?page=' + i, new list<TestCalloutResponseGenerator.Resp>{ new TestCalloutResponseGenerator.Resp( '{"Contacts":"data...' + i + '"}', 'success', 200, true) }); } // Add all of the contact responses to the response map TestCalloutResponseGenerator.getResponseMap().put('GET', pagedResponses);
  • 42. •  Setup ResponseMap •  Shortcut Explanation •  Contacts •  ContactCount •  Discard •  Set mock •  Invoke Callout Testing the Solution Example4_TestCalloutClass.TestWithPattern() // Enable mock response Test.setMock(HttpCalloutMock.class, new TestCalloutResponseGenerator()); // Invoke the callout method string results = Example4_CalloutClass.MakeCallouts(); system.debug('Results: rnrn' + results);
  • 43. Testing the Solution TestCalloutClass 1.  Count or Contact callout 2.  # of loop iteration 3.  Count data 10, 12, 12, … 1.  Use 1st, discard 2.  Use 2nd, don’t discard 4.  Contact data increments 1.  Provided per page response