salesforce 零基础学习(六十八)http callout test class写法
此篇可以参考:
https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_classes_restful_http_testing_httpcalloutmock.htm
https://developer.salesforce.com/trailhead/force_com_dev_intermediate/apex_integration_services/apex_integration_rest_callouts
在项目中我们经常会用到通过http方式和其他系统交互,在salesforce 零基础学习(三十三)通过REST方式访问外部数据以及JAVA通过rest方式访问salesforce这篇讲过http callout方式使用,
简单callout demo如下:
1 public class CalloutClass { 2 3 //default out of time 4 private static final Integer OUT_OF_TIME = 10000; 5 //default method : get 6 private static final String DEFAULT_METHOD_GET = 'GET'; 7 8 private static final Integer STATUS_CODE_OK = 200; 9 10 public static String getDataViaHttp(String endPoint,String param) { 11 return getDataViaHttp(endPoint,DEFAULT_METHOD_GET,param); 12 } 13 14 public static String getDataViaHttp(String endPoint,String method,String param) { 15 return getDataViaHttp(endPoint,method,param,OUT_OF_TIME); 16 } 17 18 public static String getDataViaHttp(String endPoint,String method,String param,Integer outOfTime) { 19 HttpRequest req = new HttpRequest(); 20 Http h = new Http(); 21 req.setMethod(method); 22 req.setHeader('Content-Type', 'application/json'); 23 if(param != null) { 24 req.setBody(param); 25 } 26 req.setEndpoint(endPoint); 27 req.setTimeout(outOfTime); 28 HttpResponse res = h.send(req); 29 if(res.getStatusCode() == STATUS_CODE_OK) { 30 return res.getBody(); 31 } else { 32 throw new CallOutException('访问失败'); 33 } 34 } 35 36 class CallOutException extends Exception { 37 38 } 39 }
有的时候我们需要在batch中调用http接口和其他系统交互进行字段更新等操作,如果在batch中需要用到http callout,需要实现Database.AllowsCallouts接口,demo如下:
1 public with sharing class CalloutBatchClass implements Database.Batchable<sObject>,Database.AllowsCallouts{ 2 public Database.QueryLocator start(Database.BatchableContext BC) { 3 String fetchSQL = 'fetch sql'; 4 return Database.getQueryLocator(fetchSQL); 5 } 6 7 public void execute(Database.BatchableContext BC, List<sObject> objList) { 8 String endPoint = 'site end point'; 9 String responseData = CalloutClass.getDataViaHttp(endPoint,null); 10 for(sObject obj : objList) { 11 //TODO 12 } 13 } 14 15 public void finish(Database.BatchableContext BC) { 16 17 } 18 }
项目中test class是必需的,而且正常要求test class覆盖率超过75%。test class中不允许http callout,我们可以通过实现HttpCalloutMock接口模拟http请求的返回值。通过重写respond方法实现
不同的http请求所返回的不同的response状态和body内容。
1 @isTest 2 global class MockHttpResponseGenerator implements HttpCalloutMock { 3 global String method; 4 5 global String METHOD1_BODY = '{"foo":"bar"}'; 6 7 global String METHOD2_BODY = '{"foo":"bar2"}'; 8 9 global MockHttpResponseGenerator() {} 10 11 12 global MockHttpResponseGenerator(String requestMethod) { 13 method = requestMethod; 14 } 15 16 // Implement this interface method 17 global HTTPResponse respond(HTTPRequest req) { 18 // Create a fake response 19 HttpResponse res = new HttpResponse(); 20 res.setHeader('Content-Type', 'application/json'); 21 String body; 22 if(method == 'method1') { 23 body = METHOD1_BODY; 24 } else if(method == 'method2') { 25 body = METHOD2_BODY; 26 } else if(method == 'methodError') { 27 res.setStatusCode(500); 28 } 29 res.setBody('{"foo":"bar"}'); 30 if(res.getStatusCode() != null) { 31 res.setStatusCode(200); 32 } 33 return res; 34 } 35 }
简单的测试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形式。
一.非并列关系:此种方式可以使用变量方式跳过相关的调用
1 public with sharing class CalloutClassUseVariable { 2 public static Boolean skipForTest{get;set;} 3 public STring getResult(String endPoint1,String endPoint2) { 4 String result1 = ''; 5 if(skipForTest == null ||skipForTest == false) { 6 result1 = CalloutClass.getDataViaHttp(endPoint1,''); 7 } 8 String result2 = CalloutClass.getDataViaHttp(endPoint2,result1); 9 return result2; 10 } 11 }
相关test class处理
1 @isTest 2 private class CalloutClassUseVariableTest { 3 static testMethod void testMethod1() { 4 Test.startTest(); 5 Test.setMock(HttpCalloutMock.class, new MockHttpResponseGenerator('method1')); 6 String endPoint = 'http://api.salesforce.com/foo/bar'; 7 CalloutClassUseVariable.skipForTest = true; 8 String result = CalloutClassUseVariable.getResult('', endPoint); 9 String expectedValue = '{"foo":"bar"}'; 10 System.assertEquals(result, expectedValue); 11 Test.stopTest(); 12 } 13 }
二.并列关系:此种方式需要使用MultiStaticResourceCalloutMock方式。
salesforce提供MultiStaticResourceCalloutMock接口实现多个callout的test class模拟response请求,可以将response的body值放在txt文档中上传至static resources中,然后test class引用相关静态资源实现模拟多个response返回。
1 public with sharing class CalloutController { 2 public String result{get;set;} 3 public void getResult(String endPoint1,String endPoint2) { 4 String result1 = CalloutClass.getDataViaHttp(endPoint1,''); 5 String result2 = CalloutClass.getDataViaHttp(endPoint2,''); 6 result = result1 + result2; 7 } 8 }
相关test class处理:
1.将需要的相关response body值上传至static resource中;
2.test class编写
1 @isTest 2 private class CalloutClassUseMultiStaticResourceTest { 3 static testMethod void testMethod1() { 4 MultiStaticResourceCalloutMock mock = new MultiStaticResourceCalloutMock(); 5 String endPoint1 = 'http://api.salesforce.com/foo/bar'; 6 String endPoint2 = 'http://api.salesforce.com/foo/sfdc'; 7 mock.setStaticResource(endPoint1, 'Callout_Method1_TestResponse'); 8 mock.setStaticResource(endPoint2, 'Callout_Method2_TestResponse'); 9 mock.setStatusCode(200); 10 mock.setHeader('Content-Type', 'application/json'); 11 Test.setMock(HttpCalloutMock.class, mock); 12 Test.startTest(); 13 CalloutController controller = new CalloutController(); 14 controller.getResult(endPoint1,endPoint2); 15 String expectedResult = '{"foo":"bar"}{"foo":"bar2"}'; 16 system.assertEquals(expectedResult,controller.result); 17 Test.stopTest(); 18 } 19 }
总结:callout test class编写可以主要看方法中对于callout执行次数以及形式,如果仅是单次请求或者非并列形式,推荐使用httpcalloutMock方式,简单粗暴,而且自己造数据,不用上传静态资源,即使在其他环境下也可以正常跑,如果进行了多次请求,并且请求之间需要有并行操作那就只能使用multi callout 形式,使用此种方式记得在移到其他平台以前将静态资源上传。如果篇中有错误地方欢迎指正,有问题欢迎留言。
转载于:https://www.cnblogs.com/zero-zyq/p/6574863.html
salesforce 零基础学习(六十八)http callout test class写法相关推荐
- salesforce 零基础学习(十八)WorkFlow介绍及用法
说起workflow大家肯定都不陌生,这里简单介绍一下salesforce中什么情况下使用workflow. 当你分配许多任务,定期发送电子邮件,记录修改时,可以通过自动配置workflow来完成以上 ...
- salesforce零基础学习(八十九)使用 input type=file 以及RemoteAction方式上传附件
在classic环境中,salesforce提供了<apex:inputFile>标签用来实现附件的上传以及内容获取.salesforce 零基础学习(二十四)解析csv格式内容中有类似的 ...
- salesforce零基础学习(九十七)Big Object
我们在salesforce学习工作中,接触到很多的 标准的 object ,自定义 object 以及外部object.我们使用SOQL / SOSL 进行搜索,熟知他们的各种limitation,查 ...
- salesforce 零基础学习(六十二)获取sObject中类型为Picklist的field values(含record type)...
本篇引用以下三个链接: http://www.tgerm.com/2012/01/recordtype-specific-picklist-values.html?m=1 https://github ...
- salesforce 零基础学习(五十四)常见异常友好消息提示
异常或者error code汇总:https://developer.salesforce.com/docs/atlas.en-us.api.meta/api/sforce_api_calls_con ...
- salesforce 零基础学习(四十二)简单文件上传下载
项目中,常常需要用到文件的上传和下载,上传和下载功能实际上是对Document对象进行insert和查询操作.本篇演示简单的文件上传和下载,理论上文件上传后应该将ID作为操作表的字段存储,这里只演示文 ...
- salesforce 零基础学习(三十四)动态的Custom Label
custom label在项目中经常用到,常用在apex class或者VF里面用来显示help text或者error message.有的时候我们需要用到的信息是动态变化的,那样就需要动态来显示信 ...
- [python opencv 计算机视觉零基础到实战] 十八、用鼠标进行画画
一.学习目标 了解如何在图片中加入文字 了解如何使用鼠标进行图像绘制 二.了解如何通过鼠标进行图像绘制 2.1 了解putText方法的使用 putText方法接收图像,文字内容, 坐标 ,字体,大小 ...
- salesforce 零基础学习(五十一)使用 Salesforce.com SOAP API 实现用户登录以及简单的增删改查(JAVA访问salesforce)...
此篇请参看:https://resources.docs.salesforce.com/202/latest/en-us/sfdc/pdf/salesforce_developer_environme ...
- Apache Flink 零基础入门(十八)Flink Table APISQL
什么是Flink关系型API? 虽然Flink已经支持了DataSet和DataStream API,但是有没有一种更好的方式去编程,而不用关心具体的API实现?不需要去了解Java和Scala的具体 ...
最新文章
- 《Adobe Flash Professional CC经典教程》——1.3 使用“库”面板
- python之路day14--列表生成式、生成器generator、生成器并行
- C# .NET Web API 如何自訂 ModelBinder
- Centos7搭建Kubernetes集群
- css button 四种状态,css中按钮的四种状态
- (zt)OpenGL中的Alpha测试,深度测试,模板测试,裁减测试
- 系统故障模拟及修复实验
- 机顶盒系统升级服务器地址,网络机顶盒怎么升级?详细教程分享
- java疯狂讲义3_java8--IO(java疯狂讲义3复习笔记)
- 2021年,学UI设计还吃香吗?
- 计算机功能清单,如何使用印象笔记的清单功能?清单快速上手教程
- 【笔记】机器视觉 光源篇
- 5.5.2指令流水线 影响因素分类
- java七行情书_七行情书
- linux软件实现看门狗,一个软件实现的Linux看门狗—soft_wdt
- 新松机器人袁_新松机器人有多大成长空间?
- Unity 2D游戏开发案例学习——Robble Swifthand(下)
- 视频编码(结构、帧内预测、帧间预测)参考自公众号Video Coding
- 相对论-再看电动力学
- 最新笔记本电脑排行榜前十名 最好的笔记本电脑排名2023
热门文章
- [软件发布]可媲美EndNote的文献管理软件与论文写作辅助软件--RefNavigator
- 推荐10个非常不错的JavaScript移动开发框架
- 使Iframe的宽高自适应,并且兼容IE 和NC浏览器- -
- 搜索数据android ui,搜索概览 | Android 开发者 | Android Developers
- mysql特效_Cocos2d-x学习笔记(16)(常见22种特效)
- Unity Bug解决分析思路
- Linux 网络编程 —— TCP编程之客户端 向服务器发送数据 接收服务器发来的数据
- mfc多文档获取版本号_管理Microsoft Office文档—基于SOLIDWORKS PDM
- mysql+mmm+主动模式_Zabbix主动代理模式 + 主动模式agent客户端
- alter table 加多个字段_多个单列索引和联合索引的区别详解