ProcessBatch测试类覆盖率不足求助:含金额条件时覆盖率仅35%
问题:批处理类添加业务条件后测试覆盖率骤降的解决方法
背景
我开发了一个实现Database.Batchable、Database.AllowsCallouts、Schedulable接口的ProcessBatch批处理类,当加入&& doc.Amount >= 50000的业务条件后,测试类覆盖率从80%降至35%,该条件符合业务需求。
批处理类代码(已修正明显语法错误)
public class ProcessBatch implements Database.Batchable<Object>, Database.AllowsCallouts, Schedulable{ public String AccountURL; public String ProcessURL; public String Key; private class JsonUpsertResult { List<Database.Error> Error {get;set;} String SFDCId{get;set;} String visibleID{get;set;} Boolean isCreated {get;set;} Boolean isSuccess {get;set;} } public ProcessBatch(){ SAP_Details__c SAP = SAP_Details__c.getOrgDefaults(); AccountURL = SAP.Account_API_URL__c; ProcessURL = SAP.Process_API_URL__c; Key = SAP.API_Key__c; System.debug('API:' + ProcessURL + '-' + Key); } public Iterable<Object> start(Database.BatchableContext BC) { List<Object> results = new List<Object>(); Http http = new Http(); HttpRequest request = new HttpRequest(); System.debug('API:' + ProcessURL + '-' + Key); request.setEndpoint(ProcessURL); request.setMethod('POST'); request.setHeader('Authorization', Key); request.setHeader('Accept', '*/*'); request.setHeader('content-type', 'application/json'); request.setBody(filters); HttpResponse response = http.send(request); if(response.getStatusCode() == 200){ SAPProcessJSON2Apex gt = (SAPProcessJSON2Apex) JSON.deserialize(response.getBody(), SAPProcessJSON2Apex.class); List<SAPProcessJSON2Apex.Result> res = gt.result; System.debug('Size of Result: ' + res.size()); results = res; } return results; } public void execute(Database.BatchableContext BC, List<Object> scope){ List<JSON2Apex.Results> accountResults = new List<JSON2Apex.Results>(); List<Process__c> ProcessToUpsert = new List<Process__c>(); List<Process_Agent__c> CollectivesToupsert = new List<Process_Agent__c>(); List<Department__c> departmentToupdate = new List<Department__c>(); List<JSON2Apex.Results> revisedAccRes = new List<JSON2Apex.Results>(); List<SAPProcessJSON2Apex.Result> res = (List<SAPProcessJSON2Apex.Result>) scope; List<SAPProcessJSON2Apex.Result> revisedRes = new List<SAPProcessJSON2Apex.Result>(); for(SAPProcessJSON2Apex.Result r : res) { SAPProcessJSON2Apex.Document doc = r.document; List<SAPProcessJSON2Apex.Companies> comp = doc.companies; List<String> processTypes = doc.processTypes; List<String> categories = doc.categories; Process__c pr = new Process__c(); pr.Visibleprocess_No__c = doc.processId; pr.Visible_method__c = 'SAP'; pr.process_Description__c = doc.description; pr.Amount__c = doc.Amount; pr.Construction_Type__c = doc.constructionType; if(doc.phase == 'First planning'){ pr.Division__c = 'First planning'; } else if(doc.phase == 'Quotation'){ pr.Division__c = 'Main Step Quotation'; } else if(doc.phase == 'Contract Get') { pr.Division__c = 'Main Step Agricultural'; } pr.process_Full_Name__c = doc.title; pr.Name = doc.title.left(80); if(categories.size() > 0){ if(categories[0] == 'Factory' || categories[0] == 'Storage'){ pr.Sector__c = 'Industrial'; } else if(categories[0] == 'Packaging/Storage') { pr.Type_of_Sector__c = 'Warehouse'; } else if(categories[0] == 'Shops and Retail' || categories[0] == 'Any Showrooms') { pr.Sector__c = 'Commercial'; } if(pr.Sector__c != null && doc.Amount >= 50000){ ProcessToUpsert.add(pr); revisedRes.add(r); } } } } public void finish(Database.BatchableContext BC) { } public void execute(SchedulableContext sc) { Database.executeBatch(new ProcessBatch(), 30); } }
现有测试类代码
@isTest(SeeAllData = true) public class ProcessBatchTest { @isTest public static void processBatchTest() { Test.setMock(HttpCalloutMock.class, new HttpMock()); ProcessBatch pb = new ProcessBatch(); Test.startTest(); Database.executeBatch(pb, 30); Test.stopTest(); } }
解决方案
1. 完善HttpMock的模拟数据
当前测试用的HttpMock没返回满足业务条件的数据集,导致execute里大部分分支没被覆盖。需要修改HttpMock,生成覆盖所有业务分支的模拟JSON:
@isTest public class HttpMock implements HttpCalloutMock { public HttpResponse respond(HttpRequest req) { HttpResponse res = new HttpResponse(); res.setStatusCode(200); // 构造覆盖所有场景的模拟数据 String jsonBody = '{ "result": [' + // 满足条件:Industrial领域、金额≥50000、First planning阶段 '{ "document": { "processId": "PROC-001", "description": "Test Industrial", "Amount": 60000, "constructionType": "New", "phase": "First planning", "title": "Factory Project", "categories": ["Factory"], "companies": [] } },' + // 满足条件:Warehouse领域、金额≥50000、Quotation阶段 '{ "document": { "processId": "PROC-002", "description": "Test Warehouse", "Amount": 75000, "constructionType": "Renovate", "phase": "Quotation", "title": "Storage Project", "categories": ["Packaging/Storage"], "companies": [] } },' + // 满足条件:Commercial领域、金额≥50000、Contract Get阶段 '{ "document": { "processId": "PROC-003", "description": "Test Commercial", "Amount": 55000, "constructionType": "New", "phase": "Contract Get", "title": "Retail Project", "categories": ["Shops and Retail"], "companies": [] } },' + // 不满足条件:领域不匹配、金额≥50000 '{ "document": { "processId": "PROC-004", "description": "Test No Sector", "Amount": 60000, "constructionType": "New", "phase": "First planning", "title": "Uncategorized", "categories": ["Other"], "companies": [] } },' + // 不满足条件:金额<50000、领域匹配 '{ "document": { "processId": "PROC-005", "description": "Test Low Amount", "Amount": 40000, "constructionType": "New", "phase": "First planning", "title": "Small Project", "categories": ["Factory"], "companies": [] } }' + '] }'; res.setBody(jsonBody); return res; } }
2. 优化测试类的断言逻辑
在测试方法里添加断言,既验证业务逻辑正确性,也确保代码分支被覆盖:
@isTest(SeeAllData = false) // 禁用SeeAllData,避免依赖生产数据 public class ProcessBatchTest { @isTest public static void processBatchTest() { // 提前创建测试用的SAP配置数据 SAP_Details__c testSAP = new SAP_Details__c( Process_API_URL__c = 'https://test-api.com/process', API_Key__c = 'test-key' ); insert testSAP; Test.setMock(HttpCalloutMock.class, new HttpMock()); ProcessBatch pb = new ProcessBatch(); Test.startTest(); Database.executeBatch(pb, 30); Test.stopTest(); // 验证符合条件的Process记录数量 List<Process__c> createdProcesses = [SELECT Id, Sector__c, Type_of_Sector__c FROM Process__c WHERE Visible_method__c = 'SAP']; System.assertEquals(3, createdProcesses.size(), '应创建3条符合条件的Process记录'); // 验证各分支是否被覆盖 Boolean hasIndustrial = false; Boolean hasWarehouse = false; Boolean hasCommercial = false; for(Process__c p : createdProcesses) { if(p.Sector__c == 'Industrial') hasIndustrial = true; if(p.Type_of_Sector__c == 'Warehouse') hasWarehouse = true; if(p.Sector__c == 'Commercial') hasCommercial = true; } System.assertEquals(true, hasIndustrial, 'Industrial分支未覆盖'); System.assertEquals(true, hasWarehouse, 'Warehouse分支未覆盖'); System.assertEquals(true, hasCommercial, 'Commercial分支未覆盖'); } }
3. 可选:提升批处理类的可测试性
如果想进一步降低测试依赖,可以给批处理类添加测试专用的构造函数,注入配置参数:
// 测试专用构造函数,跳过组织默认值查询 public ProcessBatch(String testProcessURL, String testKey) { ProcessURL = testProcessURL; Key = testKey; } // 原生产用构造函数保留 public ProcessBatch(){ SAP_Details__c SAP = SAP_Details__c.getOrgDefaults(); AccountURL = SAP.Account_API_URL__c; ProcessURL = SAP.Process_API_URL__c; Key = SAP.API_Key__c; System.debug('API:' + ProcessURL + '-' + Key); }
内容的提问来源于stack exchange,提问作者Gautam T
相关产品推荐
相关产品推荐

