Можем ли мы иметь два макета Http Callout в одном методе тестового класса

Aug 17 2020

В моем методе выполнение двух выносков в одной транзакции

  1. Получить токен доступа для этого API -> GetAccessToken
  2. Выполнить платеж

Когда я запустил тестовый класс, я получил следующую ошибку 08:50:00:839 FATAL_ERROR System.NullPointerException: Argument 2 cannot be null. в этом коде request.setHeader('Authorization', accessTokenValue);

В моем ответе на макет я устанавливаю параметр «Только при выполнении платежа». Можем ли мы смоделировать API токена доступа тем же методом. Поскольку фиктивный execute Paymentответ только класса , не может выполнить вызов токена доступа, поэтому accessTokenValueустанавливается как NULL.

Есть ли способ иметь несколько макетов в одном методе тестового класса. Направь меня на это. Спасибо

Метод:

 @AuraEnabled 
    public static boolean executepaymentbupayid(string payPalPayId , string payerid, Id familyrecId, string internalTransactionId){
        
        // string authorisation;
        string accessTokenValue;
        List<AggregateResult> aggr = [SELECT Service_Center__r.Client_ID__c,  Service_Center__r.Secret__c 
                                      ,Service_Center__r.PayPal_API__c
                                      FROM invoice__c WHERE   Student_Family__c=:familyrecId
                                      Group by Service_Center__r.Client_ID__c,  Service_Center__r.Secret__c, Service_Center__r.PayPal_API__c ];
        
        HttpResponse response = getPaypalAccessToken.GetAccessToken(String.valueOf(aggr[0].get('Client_ID__c')),String.valueOf(aggr[0].get('Secret__c')), String.valueOf(aggr[0].get('PayPal_API__c'))); 


        Map<String, Object> results = (Map<String, Object>) JSON.deserializeUntyped(response.getBody());
        if (response.getStatusCode() == 200) {           
            System.debug('results' + results.get('access_token'));
            System.debug('results' + results.get('token_type'));
            string tokentype = String.valueof(results.get('token_type'));
            string accesstoken = String.valueof(results.get('access_token'));        
            accessTokenValue = tokentype + ' ' + accesstoken;
        }
        
   
        
        executePayment executePaymentWrapper = new executePayment(); 
        executePaymentWrapper.payerid = payerid;
        String myJSON = JSON.serialize(executePaymentWrapper);
        String jsonReplacedString;
        jsonReplacedString = myJSON.replace('payerid', 'payer_id');
        
        
        string endpoint;       
        endpoint = System.Label.PayPal_Live_Execute_Payment + payPalPayId + '/execute';
     
        
        http http = new http();
        httpRequest request = new httpRequest();
        request.setMethod('POST');
        request.setEndpoint(endpoint);
        request.setHeader('Content-Type', 'application/json');
        request.setHeader('Authorization', accessTokenValue);
        request.setBody(jsonReplacedString);
        httpResponse res = http.send(request);      
        if (Res.getStatusCode() == 200){
            boolean updatePaymentReceived = paymentReceivedUpdate(familyrecId, internalTransactionId);            
            If(updatePaymentReceived){
                return true;
            }else{
                return false;
            }
        }else{
            return false;
        }        
    }

Метод испытания

    @isTest
    public static void executepaymentbupayidTest(){
        Map <string,id> testData = TestDataFactory.CreateTestDate();  
        ID familyId = TestData.get('FamilyID');
        string payPalPayId ='PAYID-L43IDSI2C58062971907464F';
        string payerid ='SDV9S3QZQQPM4';
        string internalTransactionId = 'internalTransactionId';        
        test.startTest(); 
        Test.setMock(HttpCalloutMock.class, new ExecutepaymentbupayidMock()); 
        Boolean returnValue = Invoice.executepaymentbupayid(payPalPayId, payerid, familyId, internalTransactionId);
        test.stopTest();
    }

Пробный ответ:

@istest
public class ExecutepaymentbupayidMock implements HttpCalloutMock{
    
    public HTTPResponse respond(HTTPRequest request) {
        HttpResponse response = new HttpResponse();
        response.setHeader('Content-Type', 'application/json');
        response.setBody('{"id": "PAYID-L43IDSI2C58062971907464F","intent": "sale","state": "approved","cart": "8YT815237T955371T","payer": {"payment_method": "paypal","status": "VERIFIED","payer_info": {"email": "[email protected]","first_name": "Safari","last_name": "Individual","payer_id": "SDV9S3QZQQPM4","shipping_address": {"recipient_name": "Brian Robinson","line1": "4th Floor","line2": "Unit #34","city": "San Jose","state": "CA","postal_code": "95131","country_code": "US"},"phone": "4089285295","country_code": "US"}},"transactions": [{"amount": {"total": "95.00","currency": "USD","details": {"subtotal": "95.00","shipping": "0.00","insurance": "0.00","handling_fee": "0.00","shipping_discount": "0.00"}},"payee": {"merchant_id": "JKHMJ249QW9TU","email": "[email protected]"},"description": "Invoice Number - 0401","custom": "gE9SyW893fA2bMVDUwVosLpM1gKxqkx0%2B3MqYXpEDjM841djbcYnoN9%2BIgqgdass","invoice_number": "401","item_list": {"items": [{"name": "Invoice Number - 0401","description": "Session 2 (weeks of June 29-July 2 and July 6-9)","price": "95.00","currency": "USD","tax": "0.00","quantity": 1}],"shipping_address": {"recipient_name": "Brian Robinson","line1": "4th Floor","line2": "Unit #34","city": "San Jose","state": "CA","postal_code": "95131","country_code": "US"}},"related_resources": [{"sale": {"id": "2T59651963103743W","state": "completed","amount": {"total": "95.00","currency": "USD","details": {"subtotal": "95.00","shipping": "0.00","insurance": "0.00","handling_fee": "0.00","shipping_discount": "0.00"}},"payment_mode": "INSTANT_TRANSFER","protection_eligibility": "ELIGIBLE","protection_eligibility_type": "ITEM_NOT_RECEIVED_ELIGIBLE,UNAUTHORIZED_PAYMENT_ELIGIBLE","transaction_fee": {"value": "3.06","currency": "USD"},"parent_payment": "PAYID-L43IDSI2C58062971907464F","create_time": "2020-08-14T12:39:00Z","update_time": "2020-08-14T12:39:00Z","links": [{"href": "https://api.sandbox.paypal.com/v1/payments/sale/2T59651963103743W","rel": "self","method": "GET"},{"href": "https://api.sandbox.paypal.com/v1/payments/sale/2T59651963103743W/refund","rel": "refund","method": "POST"},{"href": "https://api.sandbox.paypal.com/v1/payments/payment/PAYID-L43IDSI2C58062971907464F","rel": "parent_payment","method": "GET"}]}}]}],"create_time": "2020-08-14T12:21:29Z","update_time": "2020-08-14T12:39:00Z","links": [{"href": "https://api.sandbox.paypal.com/v1/payments/payment/PAYID-L43IDSI2C58062971907464F","rel": "self","method": "GET"}]}');
        response.setStatusCode(201);
        return response; 
    }
}

Ответы

9 DavidReed Aug 17 2020 at 10:47

Да, можно, используя любой из двух методов.

Ваш HttpCalloutMock«сек respond()метод может проверить его Входящее HttpRequestи построить иной ответ , на основании которого конечная точка вызывается, параметры , передаваемые и т.д. Это позволяет написать один класс , который возвращает ответы для нескольких выноски , сделанных в последовательности в коде тестируемой .

В качестве альтернативы вы можете использовать MultiStaticResourceCalloutMockкласс. Этот класс позволяет вам хранить тела ответов в статических ресурсах в вашем приложении и настраивать Mock для нескольких конечных точек, вызывая setStaticResource()один раз для каждой конечной точки, на которую вы хотите, чтобы Mock отвечал. Это может избавить вас от написания шаблонного кода, если вы не против хранить свои ответы в статических ресурсах, а не создавать их в коде.