【问题标题】:Salesforce: An APEX test class for a web service calloutSalesforce:Web 服务标注的 APEX 测试类
【发布时间】:2021-03-18 14:30:38
【问题描述】:

我一直在尝试找出 Web 服务标注的测试类。我有四个不同的课程。 API_Member 包含所有参数以及字段的所有信息和匹配。我有一个API_Response 类,我有一个AccountTriggerAccountTriggerHandler

AccountTriggerHandler 中,整个HTTPRequest 和标注都在我调用API_Member 类的地方处理,然后从AccountTrigger 触发它。

现在的困难是测试类,因为我不是经验丰富的开发人员。

我将如何处理这段代码的测试类(我已经进行了更改以防它是一些重要信息)?

public with sharing class AccountTriggerHandler {

    public void isAfterInsert(list<Account> accountNew) {
        for(Account a: accountNew) {
            sendData(a.Id);
        }
    }

    public void isAfterUpdate(list<Account> accountNew) {

    }

    @future(callout=true)
    public static void sendData(string accountId) {
        API_Member api = new API_Member(accountId);
        api.setupData();
        API_Member.Data data = api.dataList;
        string json = JSON.serialize(data); 
        system.debug('JSON' + json);
        Http http = new Http();
        HttpRequest request = new HttpRequest();
        string url = 'http://api.XXXXXXXXXXXXXXXXXXXXXXX';
        string username = 'Ext-XXXXXXXXXXXXXXX-XXXXXXXXXXXXXX';
        string password = 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXX';
        Blob headerValue = Blob.valueOf(username + ':' + password);
        String authorizationHeader = 'Basic ' + EncodingUtil.base64Encode(headerValue);
        request.setHeader('Authorization', authorizationHeader); 
        request.setHeader('Content-Type', 'application/json;charset=UTF-8');
        request.setEndpoint(url);
        request.setMethod('POST');
        request.setBody(json);
        HttpResponse response = http.send(request);
        if (response.getStatusCode() == 201 || response.getStatusCode() == 200 ) {
            API_Response responseCTRL = (API_Response) System.JSON.deserialize(response.getBody(), API_Response.class);
            list<API_Response.Meta> m = responseCTRL.Meta;
            System.debug('recordID='+m[0].recordID);
            api.setResponse(m[0].recordID,response.getStatus());
        }
    }
}

这里是 API_Member 类

public class API_Member {
    public Data dataList;
    public Account input;
    public Contact c;
    public class Data {
        public list<Info> data;
    }
    public class Info {
            public String active;
            public String address_city;
            public String address_country;
            public String address_line_1;
            public String address_line_2;
            public String address_state;
            public String address_zipcode;
            public String company_name;
            public String date_end;
            public String date_paid;
            public String date_start;
            public String email;
            public String membership_number;
            public String mobile;
            public String org_number;
            public String person_first_name;
            public String person_last_name;
            public String person_number;
            public String phone;
            public String status;
            public String web_address;
    }

    public API_Member(string accountId) {
        this.input = getAccount(accountId);
        this.c = getContact();
    }

    public void setupData(){
        dataList = new Data();
        Info data = new Info();
        data.active = 'true'; //To be verified
        data.address_city = input.Ort__c;
        data.address_country = '';
        data.address_line_1 = input.Adress1__c;
        data.address_line_2 = '';
        //data.address_state = input.L_n_Namn__c;
        data.address_zipcode = input.Postnummer__c;
        data.company_name = input.Name;
        data.date_end = input.Expiry_Date__c != null ? string.valueOf(input.Expiry_Date__c) : '';
        data.date_paid = input.Last_Renew__c != null ? string.valueOf(input.Last_Renew__c) : '';
        data.date_start = input.Last_Renew__c != null ? string.valueOf(input.Last_Renew__c): '';
        data.email = input.Medlems_Epost__c;
        data.membership_number = input.AccountNumber;
        data.mobile = input.Phone;
        data.org_number = input.Organisationsnummer__c;
        data.person_first_name = c != null ? c.FirstName : '';
        data.person_last_name = c != null ? c.LastName : '';
        data.person_number = c != null ? c.Personnummer__c : '';
        data.phone = input.Phone;
        data.status = input.Status_Pay__c;
        data.web_address = input.Website;

        dataList.data = new list<Info>{data};
    }

    public Contact getContact(){
        list<Contact> c = [ SELECT Id,
                            Personnummer__c,
                            LastName,
                            FirstName
                            FROM Contact
                            WHERE AccountId =: input.Id
                            ORDER BY CreatedDate
                            ASC
                            LIMIT 1
        ];
        if(c.size() > 0){
            return c[0];
        }
        return null;
    }

    public Account getAccount(string accountId){
        Account a = [SELECT Id,
                    Ort__c,
                    Adress1__c,
                    Postnummer__c,
                    Name,
                    Expiry_Date__c,
                    Last_Renew__c,
                    Medlems_Epost__c,
                    AccountNumber,
                    Phone,
                    Organisationsnummer__c,
                    Status_Pay__c,
                    F_RecordId__c,
                    F_Satus__c,
                    Website
                    FROM Account
                    WHERE Id =: accountId
                    LIMIT 1
        ];
        return a;
    }
    
    public void setResponse(string recordId, string Status) {
        input.F_RecordId__c  = recordId;
        input.F_Satus__c  = status;
        update input;
    }
}

这里是 API_Response 类

public class API_Response {

    public class Meta {
        public String recordID {get;set;} 
        public String href {get;set;} 
    }
    
    public List<Meta> meta {get;set;} 
    public List<Data> data {get;set;} 
    public Info info {get;set;} 
    public List<MetaField> metaField {get;set;} 
    
    public class MetaField {
        public String name {get;set;} 
        public Integer autoEntered {get;set;} 
        public Integer global_Z {get;set;} // in json: global
        public Integer maxRepeat {get;set;} 
        public String resultType {get;set;}         
    }
    
    public class Data {
        public String address_city {get;set;} 
        public String address_country {get;set;} 
        public String address_line_1 {get;set;} 
        public String address_line_2 {get;set;} 
        public String address_state {get;set;} 
        public String address_zipcode {get;set;} 
        public String company_name {get;set;} 
        public String date_end {get;set;} 
        public String date_start {get;set;} 
        public String email {get;set;} 
        public String membership_number {get;set;} 
        public String mobile {get;set;} 
        public String org_number {get;set;} 
        public String person_first_name {get;set;} 
        public String person_last_name {get;set;} 
        public String person_number {get;set;} 
        public String phone {get;set;} 
        public String status {get;set;} 
        public String upload_data_status {get;set;} 
        public String web_address {get;set;} 

    }
    
    public class Info {
        public String X_RESTfm_Version {get;set;} // in json: X-RESTfm-Version
        public String X_RESTfm_Protocol {get;set;} // in json: X-RESTfm-Protocol
        public Integer X_RESTfm_Status {get;set;} // in json: X-RESTfm-Status
        public String X_RESTfm_Reason {get;set;} // in json: X-RESTfm-Reason
        public String X_RESTfm_Method {get;set;} // in json: X-RESTfm-Method
        public String X_RESTfm_PHP_memory_limit {get;set;} // in json: X-RESTfm-PHP-memory_limit
        public String X_RESTfm_PHP_post_max_size {get;set;} // in json: X-RESTfm-PHP-post_max_size

    }
    
}

【问题讨论】:

    标签: salesforce apex salesforce-lightning rest callouts


    【解决方案1】:

    对于单元测试,您必须模拟(伪造)您正在调用的服务。我们不能从单元测试中调用真正的服务,因为:

    • 部署成功/失败不应取决于某些第 3 方服务器是否已关闭
    • 您不希望在没有办法回滚的情况下向生产服务器发送“my awesome test data!!!111”消息。

    您需要编写一段代码来假装它是该服务。这取决于你它会有多棒。它总是可以返回相同的消息。或者它可以检查它收到的数据,如果缺少必填字段则抛出错误。真的 - 你决定,你最清楚应该测试多少个场景(你如何处理返回的错误?)

    查看https://trailhead.salesforce.com/en/content/learn/modules/apex_integration_services/apex_integration_soap_callouts

    模拟的整个概念也可以用于“正常”顶点,而不仅仅是标注。不过可能有点高级的话题:https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_testing_stub_api.htm

    编辑:

    您需要 2 个可以标记为 @isTest 的类(因此它们不计入您的正常代码最大值)。这是 REST API,对吧?不是肥皂?也许https://trailhead.salesforce.com/content/learn/modules/apex_integration_services/apex_integration_rest_callouts 会更好。在紧要关头,您可以将其设为 1 类,但有点混乱,请将它们分开?

    首先创建API_ResponseMock。不一定非要globalpublic 就足够了。类似的东西

    @isTest
    public class API_ResponseMock implements HttpCalloutMock {
        public HTTPResponse respond(HTTPRequest request) {
            // Create a fake response
            HttpResponse response = new HttpResponse();
            response.setHeader('Content-Type', 'application/json');
            response.setBody('if you have sample JSON document that the service would return - paste it here. You must have something you used as the JSON2Apex input?');
            response.setStatusCode(200);
            return response;
        }
    

    这是基础,您可能不希望它在每个“标注”上都返回相同的内容,但已经足够了。

    AccountTriggerHandlerTest 将是“正常”单元测试,创建测试帐户。类似的东西

    @isTest
    static void testCallout() {
        // Set mock callout class 
        Test.setMock(HttpCalloutMock.class, new API_ResponseMock());
        Test.startTest();
        insert new Account(Name = 'unit test'); // put whatever required fields you have
        Test.stopTest(); // @future's don't run until this line.
    
        // hm, what now? You have anything to "assert"? Will this callout be updating account maybe? Setting a Task with status=Completed, anything you can check?
    }
    

    【讨论】:

    • 您好,感谢您的意见。我知道我需要一个模拟测试课程,但是我没有这样做的经验。我看到了一些对 web 服务标注进行模拟测试的人的例子,但是我需要知道。如果我要创建一个测试类,它是用于 AccountTriggerHandler 类还是 API_Member 类?还是我需要为他们两个都做一个测试课?
    • 感谢您的意见和您为帮助我所做的努力。我会试试这个,如果有什么我想知道的,我会回复你。
    猜你喜欢
    • 2015-11-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-11-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多