salesforce 零基础学习(六十八)http callout test class写法
此篇可以参考:
在项目中我们经常会用到通过http方式和其他系统交互,在salesforce 零基础学习(三十三)通过REST方式访问外部数据以及JAVA通过rest方式访问salesforce这篇讲过http callout方式使用,
简单callout demo如下:
public class CalloutClass {
//default out of time
private static final Integer OUT_OF_TIME = 10000;
//default method : get
private static final String DEFAULT_METHOD_GET = 'GET';
private static final Integer STATUS_CODE_OK = 200;
public static String getDataViaHttp(String endPoint,String param) {
return getDataViaHttp(endPoint,DEFAULT_METHOD_GET,param);
}
public static String getDataViaHttp(String endPoint,String method,String param) {
return getDataViaHttp(endPoint,method,param,OUT_OF_TIME);
}
public static String getDataViaHttp(String endPoint,String method,String param,Integer outOfTime) {
HttpRequest req = new HttpRequest();
Http h = new Http();
req.setMethod(method);
req.setHeader('Content-Type', 'application/json');
if(param != null) {
req.setBody(param);
}
req.setEndpoint(endPoint);
req.setTimeout(outOfTime);
HttpResponse res = h.send(req);
if(res.getStatusCode() == STATUS_CODE_OK) {
return res.getBody();
} else {
throw new CallOutException('访问失败');
}
}
class CallOutException extends Exception {
}
}
有的时候我们需要在batch中调用http接口和其他系统交互进行字段更新等操作,如果在batch中需要用到http callout,需要实现Database.AllowsCallouts接口,demo如下:
public with sharing class CalloutBatchClass implements Database.Batchable<sObject>,Database.AllowsCallouts{
public Database.QueryLocator start(Database.BatchableContext BC) {
String fetchSQL = 'fetch sql';
return Database.getQueryLocator(fetchSQL);
}
public void execute(Database.BatchableContext BC, List<sObject> objList) {
String endPoint = 'site end point';
String responseData = CalloutClass.getDataViaHttp(endPoint,null);
for(sObject obj : objList) {
//TODO
}
}
public void finish(Database.BatchableContext BC) {
}
}
项目中test class是必需的,而且正常要求test class覆盖率超过75%。test class中不允许http callout,我们可以通过实现HttpCalloutMock接口模拟http请求的返回值。通过重写respond方法实现
不同的http请求所返回的不同的response状态和body内容。
@isTest
global class MockHttpResponseGenerator implements HttpCalloutMock {
global String method; global String METHOD1_BODY = '{"foo":"bar"}'; global String METHOD2_BODY = '{"foo":"bar2"}'; global MockHttpResponseGenerator() {} global MockHttpResponseGenerator(String requestMethod) {
method = requestMethod;
} // Implement this interface method
global HTTPResponse respond(HTTPRequest req) {
// Create a fake response
HttpResponse res = new HttpResponse();
res.setHeader('Content-Type', 'application/json');
String body;
if(method == 'method1') {
body = METHOD1_BODY;
} else if(method == 'method2') {
body = METHOD2_BODY;
} else if(method == 'methodError') {
res.setStatusCode(500);
}
res.setBody('{"foo":"bar"}');
if(res.getStatusCode() != null) {
res.setStatusCode(200);
}
return res;
}
}
简单的测试CalloutClass的测试类如下:
@isTest
private class CalloutClassTest {
@isTest static void testSuccessCallout() {
Test.startTest();
// Set mock callout class
Test.setMock(HttpCalloutMock.class, new MockHttpResponseGenerator('method1'));
String endPoint = 'http://api.salesforce.com/foo/bar';
String result = CalloutClass.getDataViaHttp(endPoint,'test param');
String expectedValue = '{"foo":"bar"}';
System.assertEquals(result, expectedValue);
Test.stopTest();
}
}
这只是我们碰到的所谓最理想的情况,有的时候我们往往会碰到这样一种情况:一个方法里面需要调用到多个http callout。比如需要先进行http callout,将返回值作为参数或者oauth setting内容然后继续进行callout,这种情况下使用上述的方式便比较难实现,毕竟上述mock形式仅作为一个http callout的response。这个时候我们要变通一下,看看前面的调用是否是必要的--前后几次调用是否有并列关系,还是仅将前几次调用作为相关参数为最后一次做准备,此种情况下,可以在类中设置相关的静态变量来跳过相关的调用;如果前后几次调用属于并列关系,需要对每一次的response的内容进行相关处理,这种情况下的test class便需要使用multi mock形式。
一.非并列关系:此种方式可以使用变量方式跳过相关的调用
public with sharing class CalloutClassUseVariable {
public static Boolean skipForTest{get;set;}
public STring getResult(String endPoint1,String endPoint2) {
String result1 = '';
if(skipForTest == null ||skipForTest == false) {
result1 = CalloutClass.getDataViaHttp(endPoint1,'');
}
String result2 = CalloutClass.getDataViaHttp(endPoint2,result1);
return result2;
}
}
相关test class处理
@isTest
private class CalloutClassUseVariableTest {
static testMethod void testMethod1() {
Test.startTest();
Test.setMock(HttpCalloutMock.class, new MockHttpResponseGenerator('method1'));
String endPoint = 'http://api.salesforce.com/foo/bar';
CalloutClassUseVariable.skipForTest = true;
String result = CalloutClassUseVariable.getResult('', endPoint);
String expectedValue = '{"foo":"bar"}';
System.assertEquals(result, expectedValue);
Test.stopTest();
}
}
二.并列关系:此种方式需要使用MultiStaticResourceCalloutMock方式。
salesforce提供MultiStaticResourceCalloutMock接口实现多个callout的test class模拟response请求,可以将response的body值放在txt文档中上传至static resources中,然后test class引用相关静态资源实现模拟多个response返回。
public with sharing class CalloutController {
public String result{get;set;}
public void getResult(String endPoint1,String endPoint2) {
String result1 = CalloutClass.getDataViaHttp(endPoint1,'');
String result2 = CalloutClass.getDataViaHttp(endPoint2,'');
result = result1 + result2;
}
}
相关test class处理:
1.将需要的相关response body值上传至static resource中;
2.test class编写
@isTest
private class CalloutClassUseMultiStaticResourceTest {
static testMethod void testMethod1() {
MultiStaticResourceCalloutMock mock = new MultiStaticResourceCalloutMock();
String endPoint1 = 'http://api.salesforce.com/foo/bar';
String endPoint2 = 'http://api.salesforce.com/foo/sfdc';
mock.setStaticResource(endPoint1, 'Callout_Method1_TestResponse');
mock.setStaticResource(endPoint2, 'Callout_Method2_TestResponse');
mock.setStatusCode(200);
mock.setHeader('Content-Type', 'application/json');
Test.setMock(HttpCalloutMock.class, mock);
Test.startTest();
CalloutController controller = new CalloutController();
controller.getResult(endPoint1,endPoint2);
String expectedResult = '{"foo":"bar"}{"foo":"bar2"}';
system.assertEquals(expectedResult,controller.result);
Test.stopTest();
}
}
总结:callout test class编写可以主要看方法中对于callout执行次数以及形式,如果仅是单次请求或者非并列形式,推荐使用httpcalloutMock方式,简单粗暴,而且自己造数据,不用上传静态资源,即使在其他环境下也可以正常跑,如果进行了多次请求,并且请求之间需要有并行操作那就只能使用multi callout 形式,使用此种方式记得在移到其他平台以前将静态资源上传。如果篇中有错误地方欢迎指正,有问题欢迎留言。
salesforce 零基础学习(六十八)http callout test class写法的更多相关文章
- salesforce 零基础学习(十八)WorkFlow介绍及用法
说起workflow大家肯定都不陌生,这里简单介绍一下salesforce中什么情况下使用workflow. 当你分配许多任务,定期发送电子邮件,记录修改时,可以通过自动配置workflow来完成以上 ...
- salesforce 零基础学习(十六)Validation Rules & Date/time
上一篇介绍的内容为Formula,其中的Date/time部分未指出,此篇主要介绍Date/time部分以及Validation rules. 本篇参考PDF: Date/time:https://r ...
- salesforce 零基础学习(十九)Permission sets 讲解及设置
Permission sets以及Profile是常见的设置访问权限的方式. Profile规则为'who see what'.通过Profile可以将一类的用户设置相同的访问权限.对于有着相同Pro ...
- salesforce零基础学习(九十八)Type浅谈
在Salesforce的世界,凡事皆Metadata. 先通过一句经常使用的代码带入一下: Account accountItem = (Account)JSON.deserialize(accoun ...
- salesforce零基础学习(九十八)Salesforce Connect & External Object
本篇参考: https://trailhead.salesforce.com/en/content/learn/modules/lightning_connect https://help.sales ...
- salesforce零基础学习(八十)使用autoComplete 输入内容自动联想结果以及去重实现
项目中,我们有时候会需要实现自动联想功能,比如我们想输入用户或者联系人名称,去联想出系统中有的相关的用户和联系人,当点击以后获取相关的邮箱或者其他信息等等.这种情况下可以使用jquery ui中的au ...
- salesforce零基础学习(八十二)审批邮件获取最终审批人和审批意见
项目中,审批操作无处不在.配置审批流时,我们有时候会用到queue,related user设置当前步骤的审批人,审批人可以一个或者多个.当审批人有多个时,邮件中获取当前记录的审批人和审批意见就不能随 ...
- salesforce零基础学习(八十九)使用 input type=file 以及RemoteAction方式上传附件
在classic环境中,salesforce提供了<apex:inputFile>标签用来实现附件的上传以及内容获取.salesforce 零基础学习(二十四)解析csv格式内容中有类似的 ...
- salesforce零基础学习(八十七)Apex 中Picklist类型通过Control 字段值获取Dependent List 值
注:本篇解决方案内容实现转自:http://mysalesforceescapade.blogspot.com/2015/03/getting-dependent-picklist-values-fr ...
随机推荐
- devexpress设置系统全局字体(含工具栏字体)
1.许多时候,都需要设置系统的字体.devexpress设置字体效果图比较如下: 上图比较可以看出,字体应用到了所有控件. 2.数据绑定代码: DataTable dt = new DataTable ...
- 简单工厂模式,工厂方法模式,抽象工厂模式,spring的狂想
菜鸟D在项目中遇见一个比较纠结的高耦合,所以就想办法来解耦.情况是这样的:系统通过用户选择treeview控件的节点判断调用不同的处理,这些处理中某些东西又是类似的.同事的建议是采用简单工厂,耦合就耦 ...
- BZOJ 1337: 最小圆覆盖1336: [Balkan2002]Alien最小圆覆盖(随机增量法)
今天才知道有一种东西叫随机增量法就来学了= = 挺神奇的= = A.令ci为包括前i个点的最小圆,若第i+1个点无法被ci覆盖,则第i+1个点一定在ci+1上 B.令ci为包括前i个点的最小圆且p在边 ...
- CORS(跨域资源共享)
Cors(Cross-origin Resource Sharing)基本思想是使用自定义的HTTP头部允许浏览器和服务器相互了解对方,从而决定响应成功与否. CORS与JSONP对比: 1.JSON ...
- Java代码块详解
Java中代码块指的是用 {} 包围的代码集合,分为4种:普通代码块,静态代码块,同步代码块,构造代码块 普通代码块: 定义:在方法.循环.判断等语句中出现的代码块 修饰:只能用标签修饰 位置:普通代 ...
- C#调用PB写的com组件dll
背景 小编为了使用C#去模仿PB代码的加密算法,结果发现PB算法中,的long类型只有21亿,实际上传入的数值达到了78亿,造成了数据溢出,精度丢失的情况. 然而PB的算法已经使用C#不可以还原(C# ...
- JQuery实现Ajax跨域访问--Jsonp原理
JavaScript是一种在Web开发中经常使用的前端动态脚本技术.在JavaScript中,有一个很重要的安全性限制,被称为“Same-Origin Policy”(同源策略).这一策略对于Java ...
- HTML5之多媒体
概览 html5新增了两个关于多媒体的元素:video和audio,前者是用于视频,后者用于音频.而他们使用非常简单 <audio src="xhn.mp3" control ...
- Cocos2d-x shader学习3: sprite描边(Outline)
Cocos2d-x 3.x的label使用了freetype字体引擎(http://www.freetype.org/),可以很轻松的实现描边和阴影效果.所以本篇文章只针对于sprite来实现描边效果 ...
- 用json传值时,最后一个不加逗号
<javascript> $('.obj').css( 'position':'relative', 'top':'100px', 'left':'100px' ); </javas ...