A while ago SF began failing tests that make callouts without an HTTP mock. When they did that we were unable to deploy some trigger as a managed package made a callout whenever an Opportunity was inserted and thus the trigger test failed due to the callout. Unfortunately there was no way to tell the managed package to not make the callout.
I worked with the dev team to add a custom setting to allow us to bypass it.
This question prompted me to revisit the issue: Writing tests for Managed Package
What I did:
Created a managed package: https://login.salesforce.com/packaging/installPackage.apexp?p0=04t6A000000V12L
I had to add a dummy class to it as it would not let me upload with only the test class so ignore those
Mock Impl Class In package
@isTest global class EchoHttpMock implements HttpCalloutMock { HttpResponse res; global EchoHttpMock(HttpResponse r) { res = r; } // This is the HttpCalloutMock interface method global HttpResponse respond(HttpRequest req) { system.debug(res.getBody()); return res; } global static void setTestMockResponse(Integer statusCode, String status, String body) { HttpResponse mockResp = new HttpResponse(); if (statusCode != null) mockResp.setStatusCode(statusCode); if (status != null) mockResp.setStatus(status); if (body != null) mockResp.setBody(body); test.setMock( HttpCalloutMock.class, New EchoHttpMock(mockResp) ); } }
Managed Callout Class
global class managed_googleCallout{ global static void doIt(){ HTTPRequest req = New HTTPRequest(); req.setEndpoint('http://www.google.com'); req.setMethod('GET'); system.debug(New Http().send(req).getBody()); } }
You can install this package in your org to validate this does not work.
I installed the package in my play org
I created a class that made a callout
Callout Class
public class local_googleCallout{ public static void doIt(){ HTTPRequest req = New HTTPRequest(); req.setEndpoint('http://www.google.com'); req.setMethod('GET'); system.debug(New Http().send(req).getBody()); } }
Pretty simple (make sure you add the endpoint to remote site settings)
I made a local copy of the EchoHttpMock in the org using the name local_EchoHttpMock
I created a test class
Local Test Class
@isTest public class googleCalloutTest{ public static testmethod void calloutTestManaged(){ test.startTest(); mockimpltest.EchoHttpMock.setTestMockResponse(200,'OK','The Body'); local_googleCallout.doIt(); test.stopTest(); } public static testmethod void calloutTestLocal(){ test.startTest(); local_EchoHttpMock.setTestMockResponse(200,'OK','The Body'); local_googleCallout.doIt(); test.stopTest(); } public static testmethod void calloutTestFromLocal_Managed(){ test.startTest(); mockimpltest.EchoHttpMock.setTestMockResponse(200,'OK','The Body'); mockimpltest.managed_googleCallout.doIt(); test.stopTest(); } }
I ran the test class and the local passes and the managed fails.
So, how is one supposed to implement a mock implementation from a managed package to support a callout during local test methods? If one wants to supply a testing framework to return particular responses to customers code / implementation it cannot be done.
Salesforce says this is supposed to work but I cannot get it to despite various attempts.
Update
Per Daniels comment, I added a class in the managed package that does a callout. When the mock implementation is implemented locally and the managed method is called the test does pass.
So it seems that only when local code is attempting to implement the callout and the mock implementation is when this occurs.
The initial observation when a trigger caused the callout
Update 3
As long as the callout originates from and the mock are implemented in the same namespace it works:
- Callout Local - > Mock Managed -> Fail
- Callout Managed -> Mock Local -> Fail
- Callout Local -> Mock Local -> Pass (obviously)
- Callout Managed -> Mock Managed -> Pass
API Version 39.0