You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何单元测试由自定义元数据控制的Apex HTTP调用模拟逻辑?

解决Apex单元测试中自定义元数据类型(MDT)依赖环境的问题

针对你遇到的单元测试依赖环境中MDT记录的问题,这里有几个实用的解决方案:

方案1:测试类中动态创建专属MDT记录

Apex测试支持通过Metadata API在测试上下文里临时创建MDT记录,测试结束后这些记录会自动清理,不会影响生产环境。这种方式完全隔离了测试与现有环境的依赖。

示例代码:

@IsTest
private class HttpCalloutTest {
    @IsTest
    static void testMockResponseFromMDT() {
        // 构建要创建的MDT记录
        My_Custom_MDT__mdt testMDT = new My_Custom_MDT__mdt(
            DeveloperName = 'Test_Response',
            Label = 'Test Response',
            Static_JSON__c = '{"status":"success","data":"test"}'
        );
        
        // 准备部署请求
        Metadata.DeployContainer container = new Metadata.DeployContainer();
        container.addMetadata(testMDT);
        
        // 执行部署并等待完成
        Id deployId = Metadata.Operations.enqueueDeployment(container, null);
        Test.waitForDeploy(deployId);
        
        // 验证部署结果
        Metadata.DeployResult result = Metadata.Operations.checkDeployStatus(deployId, true);
        System.assert(result.isSuccess(), 'MDT部署失败: ' + result.getErrorMessage());
        
        // 开启模拟开关,执行业务逻辑测试
        My_Custom_Setting__c setting = My_Custom_Setting__c.getOrgDefaults();
        setting.Enable_Mock__c = true;
        update setting;
        
        // 调用待测试的HTTP调用方法
        HttpResponse response = MyHttpCalloutService.makeCallout();
        
        // 断言响应是否符合MDT中的静态JSON
        System.assertEquals('{"status":"success","data":"test"}', response.getBody());
    }
}

方案2:抽象MDT读取逻辑,测试时注入模拟实现

通过面向接口编程,把读取MDT的逻辑和业务逻辑解耦,测试时直接使用模拟的响应数据,完全绕开MDT的依赖。

步骤:

  1. 定义响应提供接口
public interface HttpResponseProvider {
    String getMockResponse();
}
  1. 生产环境实现(读取MDT)
public class MetadataResponseProvider implements HttpResponseProvider {
    public String getMockResponse() {
        My_Custom_MDT__mdt mdtRecord = My_Custom_MDT__mdt.getInstance('Default_Response');
        return mdtRecord?.Static_JSON__c;
    }
}
  1. 测试用模拟实现
@IsTest
private class MockResponseProvider implements HttpResponseProvider {
    public String getMockResponse() {
        return '{"status":"success","data":"mock_test"}';
    }
}
  1. 业务逻辑类依赖注入
public class MyHttpCalloutService {
    private static HttpResponseProvider provider;
    
    // 生产环境默认使用MDT实现
    static {
        provider = new MetadataResponseProvider();
    }
    
    // 测试时调用此方法替换为模拟实现
    @TestVisible
    private static void setProvider(HttpResponseProvider customProvider) {
        provider = customProvider;
    }
    
    public static HttpResponse makeCallout() {
        My_Custom_Setting__c setting = My_Custom_Setting__c.getOrgDefaults();
        if(setting.Enable_Mock__c) {
            HttpResponse mockResponse = new HttpResponse();
            mockResponse.setBody(provider.getMockResponse());
            mockResponse.setStatusCode(200);
            return mockResponse;
        } else {
            // 真实HTTP调用逻辑
            HttpRequest req = new HttpRequest();
            // ... 设置请求参数
            Http http = new Http();
            return http.send(req);
        }
    }
}
  1. 测试类使用模拟实现
@IsTest
private class HttpCalloutTest {
    @IsTest
    static void testMockResponse() {
        // 替换为模拟提供者
        MyHttpCalloutService.setProvider(new MockResponseProvider());
        
        // 开启模拟开关
        My_Custom_Setting__c setting = My_Custom_Setting__c.getOrgDefaults();
        setting.Enable_Mock__c = true;
        update setting;
        
        HttpResponse response = MyHttpCalloutService.makeCallout();
        System.assertEquals('{"status":"success","data":"mock_test"}', response.getBody());
    }
}

方案3:使用Test.loadData导入静态资源中的测试数据

将测试用的MDT数据预定义为JSON格式的静态资源,测试时通过Test.loadData导入,无需手动创建MDT记录。

步骤:

  1. 创建静态资源(比如命名为MDT_Test_Data),内容为:
[
    {
        "DeveloperName": "Test_Response",
        "Label": "Test Response",
        "Static_JSON__c": "{\"status\":\"success\",\"data\":\"load_data_test\"}"
    }
]
  1. 测试类中加载数据
@IsTest
private class HttpCalloutTest {
    @IsTest
    static void testMockResponseFromLoadedMDT() {
        // 从静态资源加载MDT测试数据
        List<SObject> mdtRecords = Test.loadData(My_Custom_MDT__mdt.SObjectType, 'MDT_Test_Data');
        System.assert(!mdtRecords.isEmpty(), '未加载到MDT测试数据');
        
        // 开启模拟开关并执行测试
        My_Custom_Setting__c setting = My_Custom_Setting__c.getOrgDefaults();
        setting.Enable_Mock__c = true;
        update setting;
        
        HttpResponse response = MyHttpCalloutService.makeCallout();
        System.assertEquals('{"status":"success","data":"load_data_test"}', response.getBody());
    }
}

这三个方案中,方案2的解耦程度最高,完全避免了对MDT环境的依赖;方案1和3则更贴近生产逻辑,适合需要验证MDT读取流程的场景。

内容的提问来源于stack exchange,提问作者Xi Xiao

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 19:31:11