salesforce学习笔记(2)- 多次调用外部接口(Multiple Http Callouts)测试类的编写

项目中我们经常遇到,在同一个方法中,多次调用外部api接口,与外部系统进行交互。

实例:

当调用某一目标外部接口时,要先获取调用此接口的Access token(全局唯一接口调用凭据)

请求1:用来获取Access token

请求信息1:

https请求方式 endpoint
GET https://api.testapi.com/bin/?XXXXXX/get_token

 

 

请求参数1:

参数 必须 说明
grant_type true 获取access_token填写client_credential
appid false  
secret true 唯一凭证密钥(appsecret)

 

 

 

 

返回值1:
{"access_token":"ACCESS_TOKEN","expires_in":7200}

 

请求2:在获取此Access token后,access_token将作为参数,进行下一步的接口调用

请求信息2:

https请求方式 endpoint
POST https://api.excuteapi.com/XXXXXX/excute

 

 

请求参数2:

参数 必须 说明
...... ...... ......
x-token true 上述access_token经过处理后作成的参数

 

 

 

返回值2:

......

上述过程落实到代码如下:

 1 public with sharing class MultipleCalloutFunction {
 2     
 3     // 取得access_token
 4     public static TokenResponse getAccessToken() {
 5         HttpRequest req = new HttpRequest();
 6         String body = 'grant_type=' + granttype + '&appid=' + appid + '&secret=' + 'appsecret';
 7         req.setMethod('GET');
 8         req.setEndpoint('https://api.testapi.com/bin/?XXXXXX/get_token');
 9         req.setHeader('Content-Type', 'application/x-www-form-urlencoded');
10         req.setBody(body);
11         Http http = new Http();
12         HttpResponse res = http.send(req);
13         if (res.getStatusCode() != 200) {
14             return null;
15         }
16         String resbody = res.getBody();
17 
18         TokenResponse tokenResponse = (TokenResponse)JSON.deserialize(resbody, TokenResponse.class);
19         return tokenResponse;
20     }
21 
22     public static void excuteMultipleCallout(List<Obj__c> objList) {
23         // 其他逻辑
24         ......
25         
26         TestRequest reqBody = new TestRequest();
27         reqBody.XXX = YYY;
28 
29         HttpRequest req = new HttpRequest();
30         req.setMethod('POST');
31         req.setEndpoint('https://api.excuteapi.com/XXXXXX/excute');
32         req.setHeader('Content-Type','application/json');
33         // access_token
34         req.setHeader('x-token', MultipleCalloutFunction.accessToken);
35         req.setBody(JSON.serialize(reqBody));
36         Http http = new Http();
37         HttpResponse response = http.send(req);
38 
39         // 后续逻辑
40         ......
41     }
42 
43     public class TokenResponse {
44         public Integer code{get;set;}
45         public String message{get;set;}
46         public Boolean success{get;set;}
47         public TokenResponseData data{get;set;}
48     }
49 
50     public class TokenResponseData {
51         public String accessToken{get;set;}
52         public Integer expiresIn{get;set;}
53     }
54 }

由于测试类中是不允许直接发送http请求的,因此,为了模拟这种情况,我们选择通过实现HttpCalloutMock接口,来获取实际情况中所需要的返回值,测试类代码如下:

 1 @IsTest
 2 private class MultipleCalloutFunctionTest {
 3 
 4     @isTest
 5     static void testGetAccessToken() {
 6         Test.startTest();
 7         Test.setMock(HttpCalloutMock.class, new MockHttpResponseGeneratorTest());
 8         MultipleCalloutFunction.TokenResponse tokenResponse = MultipleCalloutFunction.getAccessToken();
 9         Test.stopTest();
10     }
11 
12     @IsTest
13     static void testExcuteMultipleCallout() {
14         // 创建测试数据
15         List<Obj__c> objList = new List<Obj__c>();
16         Obj__c obj = new Obj__c();
17         obj.Field1__c = 'a';
18         obj.Field2__c = 'b';
19         objList.add(obj);
20         insert objList;
21 
22         Test.startTest();
23         Test.setMock(HttpCalloutMock.class, new MockHttpResponseGeneratorTest());
24         MultipleCalloutFunction.excuteMultipleCallout(objList);
25         Test.stopTest();
26     }
27     
28     private class MockHttpResponseGeneratorTest implements HttpCalloutMock {
29         public HTTPResponse respond(HTTPRequest req) {
30             // 根据endpoint来区分返回值
31             if (req.getEndpoint().endsWith('token')) {
32                 // 创建一个假的返回值
33                 HttpResponse res = new HttpResponse();
34                 res.setHeader('Content-Type', 'application/json');
35                 res.setBody('{"code":0,"data":{"accessToken":"afd454d-dsd84gfs-ds4fs4d5","expiresIn":23000},"message":取得accesstoken成功,"success":true}');
36                 res.setStatusCode(200);
37                 return res;
38             } else if (req.getEndpoint().endsWith('excute')) {
39                 HTTPResponse res = new HTTPResponse();
40                 // 这里的返回值可以根据真实情况去设定
41                 res.setBody('{"code":0,"data":"xxxx","message":xxxxxxxx,"success":true}');
42                 res.setStatusCode(200);
43                 return res;
44             } else {
45                 System.assert(false, 'unexpected endpoint ' + req.getEndpoint());
46                 return null;
47             }
48         }
49     }
50 
51 }

总结:

单个callout或者多个callout的场景,测试类写法与常规测试类写法还是有区别的,把握了HttpCalloutMock的方向且清楚根据endpoint来区分返回值,问题就迎刃而解了。

 

Copyright © 乔木船长

博客主页:https://www.cnblogs.com/captainqiaomu/

posted on 2023-04-04 17:21  乔木船长  阅读(80)  评论(0编辑  收藏  举报

导航