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

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

实例:

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

请求1:用来获取Access token

请求信息1:

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

请求参数1:

参数必须说明
grant_typetrue获取access_token填写client_credential
appidfalse
secrettrue唯一凭证密钥(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-tokentrue上述access_token经过处理后作成的参数

返回值2:

......

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

public with sharing class MultipleCalloutFunction {

    // 取得access_token
    public static TokenResponse getAccessToken() {
        HttpRequest req = new HttpRequest();
        String body = 'grant_type=' + granttype + '&appid=' + appid + '&secret=' + 'appsecret';
        req.setMethod('GET');
        req.setEndpoint('https://api.testapi.com/bin/?XXXXXX/get_token');
        req.setHeader('Content-Type', 'application/x-www-form-urlencoded');
        req.setBody(body);
        Http http = new Http();
        HttpResponse res = http.send(req);
        if (res.getStatusCode() != 200) {
            return null;
        }
        String resbody = res.getBody();

        TokenResponse tokenResponse = (TokenResponse)JSON.deserialize(resbody, TokenResponse.class);
        return tokenResponse;
    }

    public static void excuteMultipleCallout(List<Obj__c> objList) {
        // 其他逻辑
        ......

        TestRequest reqBody = new TestRequest();
        reqBody.XXX = YYY;

        HttpRequest req = new HttpRequest();
        req.setMethod('POST');
        req.setEndpoint('https://api.excuteapi.com/XXXXXX/excute');
        req.setHeader('Content-Type','application/json');
        // access_token
        req.setHeader('x-token', MultipleCalloutFunction.accessToken);
        req.setBody(JSON.serialize(reqBody));
        Http http = new Http();
        HttpResponse response = http.send(req);

        // 后续逻辑
        ......
    }

    public class TokenResponse {
        public Integer code{get;set;}
        public String message{get;set;}
        public Boolean success{get;set;}
        public TokenResponseData data{get;set;}
    }

    public class TokenResponseData {
        public String accessToken{get;set;}
        public Integer expiresIn{get;set;}
    }
}

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

@IsTest
private class MultipleCalloutFunctionTest {

    @isTest
    static void testGetAccessToken() {
        Test.startTest();
        Test.setMock(HttpCalloutMock.class, new MockHttpResponseGeneratorTest());
        MultipleCalloutFunction.TokenResponse tokenResponse = MultipleCalloutFunction.getAccessToken();
        Test.stopTest();
    }

    @IsTest
    static void testExcuteMultipleCallout() {
        // 创建测试数据
        List<Obj__c> objList = new List<Obj__c>();
        Obj__c obj = new Obj__c();
        obj.Field1__c = 'a';
        obj.Field2__c = 'b';
        objList.add(obj);
        insert objList;

        Test.startTest();
        Test.setMock(HttpCalloutMock.class, new MockHttpResponseGeneratorTest());
        MultipleCalloutFunction.excuteMultipleCallout(objList);
        Test.stopTest();
    }

    private class MockHttpResponseGeneratorTest implements HttpCalloutMock {
        public HTTPResponse respond(HTTPRequest req) {
            // 根据endpoint来区分返回值
            if (req.getEndpoint().endsWith('token')) {
                // 创建一个假的返回值
                HttpResponse res = new HttpResponse();
                res.setHeader('Content-Type', 'application/json');
                res.setBody('{"code":0,"data":{"accessToken":"afd454d-dsd84gfs-ds4fs4d5","expiresIn":23000},"message":取得accesstoken成功,"success":true}');
                res.setStatusCode(200);
                return res;
            } else if (req.getEndpoint().endsWith('excute')) {
                HTTPResponse res = new HTTPResponse();
                // 这里的返回值可以根据真实情况去设定
                res.setBody('{"code":0,"data":"xxxx","message":xxxxxxxx,"success":true}');
                res.setStatusCode(200);
                return res;
            } else {
                System.assert(false, 'unexpected endpoint ' + req.getEndpoint());
                return null;
            }
        }
    }

}

总结:

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

Copyright © 乔木船长

个人主页:乔木船长

欢迎转发点评和指正!

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值