如何将Apex控制器DocumentSelectorController测试覆盖率提升至75%以上
提升DocumentSelectorController测试覆盖率的解决方案
核心问题分析
getChildObjects方法仅覆盖到Id recordId = hostId;,说明未正确模拟依赖的元数据和Helper类返回结果,导致后续CreateRelatedSettingHelper.getCreateRelatedSetting、getSOQLQuery及Database.query逻辑未执行,直接进入catch块。releaseDocument和releaseChildDocuments包含大量switch分支与if条件,未覆盖所有分支路径是覆盖率不足的主要原因。
测试类编写关键步骤
- 插入测试用自定义元数据:构造不同配置的
dmpl__CreateRelatedSetting__mdt记录,覆盖所有HostObject、RelatedObject、Tag组合。 - 构造业务对象测试数据:创建
dmpl__SaleOrder__c、dmpl__InventoryFulfillment__c等业务对象的测试记录,满足Helper类方法的入参要求。 - 覆盖正常与异常分支:既测试方法正常执行的场景,也模拟异常触发(如无效Id、空元数据)覆盖catch块。
完整测试类代码
@isTest private class DocumentSelectorControllerTest { @testSetup static void setupTestData() { // 插入自定义元数据记录,覆盖不同分支场景 insert new dmpl__CreateRelatedSetting__mdt( MasterLabel = 'SaleOrder to InventoryFulfillment', dmpl__HostObjectId__c = Schema.dmpl__SaleOrder__c.SObjectType.getDescribe().getKeyPrefix(), dmpl__RelatedObjectId__c = Schema.dmpl__InventoryFulfillment__c.SObjectType.getDescribe().getKeyPrefix(), dmpl__Tag__c = '' ); insert new dmpl__CreateRelatedSetting__mdt( MasterLabel = 'SaleOrder OTC to SaleInvoice', dmpl__HostObjectId__c = Schema.dmpl__SaleOrder__c.SObjectType.getDescribe().getKeyPrefix(), dmpl__RelatedObjectId__c = Schema.dmpl__SaleInvoice__c.SObjectType.getDescribe().getKeyPrefix(), dmpl__Tag__c = 'OTC' ); insert new dmpl__CreateRelatedSetting__mdt( MasterLabel = 'InventoryFulfillment to DeliveryOrder', dmpl__HostObjectId__c = Schema.dmpl__InventoryFulfillment__c.SObjectType.getDescribe().getKeyPrefix(), dmpl__RelatedObjectId__c = Schema.dmpl__DeliveryOrder__c.SObjectType.getDescribe().getKeyPrefix(), dmpl__Tag__c = '' ); // 插入业务对象测试记录 dmpl__SaleOrder__c testOrder = new dmpl__SaleOrder__c(Name = 'Test Order 001'); insert testOrder; dmpl__InventoryFulfillment__c testFulfillment = new dmpl__InventoryFulfillment__c( Name = 'Test Fulfillment 001', dmpl__SaleOrder__c = testOrder.Id ); insert testFulfillment; } static testMethod void testGetCreateRelatedSettings() { // 测试正常场景 Test.startTest(); List<dmpl__CreateRelatedSetting__mdt> settings = DocumentSelectorController.getCreateRelatedSettings('dmpl__SaleOrder__c'); Test.stopTest(); System.assertNotEquals(null, settings); // 测试异常场景 Test.startTest(); try { DocumentSelectorController.getCreateRelatedSettings('InvalidObject'); System.assert(false, 'Expected exception not thrown'); } catch (Exception e) { System.assert(true); } Test.stopTest(); } static testMethod void testGetChildObjects() { // 获取测试元数据Id dmpl__CreateRelatedSetting__mdt testSetting = [SELECT Id FROM dmpl__CreateRelatedSetting__mdt WHERE MasterLabel = 'SaleOrder to InventoryFulfillment']; dmpl__SaleOrder__c testOrder = [SELECT Id FROM dmpl__SaleOrder__c LIMIT 1]; // 测试正常场景(假设CreateRelatedSettingHelper.getSOQLQuery返回合法查询) Test.startTest(); List<SObject> childObjects = DocumentSelectorController.getChildObjects(testSetting.Id, testOrder.Id, 'Test'); Test.stopTest(); System.assertNotEquals(null, childObjects); // 测试异常场景(无效元数据Id) Test.startTest(); try { DocumentSelectorController.getChildObjects('000000000000000AAA', testOrder.Id, 'Test'); System.assert(false, 'Expected exception not thrown'); } catch (Exception e) { System.assert(true); } Test.stopTest(); } static testMethod void testReleaseDocument() { // 测试SaleOrder -> InventoryFulfillment分支 dmpl__CreateRelatedSetting__mdt setting1 = [SELECT Id FROM dmpl__CreateRelatedSetting__mdt WHERE MasterLabel = 'SaleOrder to InventoryFulfillment']; dmpl__SaleOrder__c testOrder = [SELECT Id FROM dmpl__SaleOrder__c LIMIT 1]; Test.startTest(); CreateRelatedResult result1 = DocumentSelectorController.releaseDocument(setting1.Id, testOrder.Id); Test.stopTest(); System.assertNotEquals(null, result1); // 测试SaleOrder OTC -> SaleInvoice分支 dmpl__CreateRelatedSetting__mdt setting2 = [SELECT Id FROM dmpl__CreateRelatedSetting__mdt WHERE MasterLabel = 'SaleOrder OTC to SaleInvoice']; Test.startTest(); CreateRelatedResult result2 = DocumentSelectorController.releaseDocument(setting2.Id, testOrder.Id); Test.stopTest(); System.assertNotEquals(null, result2); // 测试InventoryFulfillment -> DeliveryOrder分支 dmpl__CreateRelatedSetting__mdt setting3 = [SELECT Id FROM dmpl__CreateRelatedSetting__mdt WHERE MasterLabel = 'InventoryFulfillment to DeliveryOrder']; dmpl__InventoryFulfillment__c testFulfillment = [SELECT Id FROM dmpl__InventoryFulfillment__c LIMIT 1]; Test.startTest(); CreateRelatedResult result3 = DocumentSelectorController.releaseDocument(setting3.Id, testFulfillment.Id); Test.stopTest(); System.assertNotEquals(null, result3); // 测试无匹配分支场景 dmpl__CreateRelatedSetting__mdt setting4 = new dmpl__CreateRelatedSetting__mdt( MasterLabel = 'Unmatched Setting', dmpl__HostObjectId__c = Schema.Account.SObjectType.getDescribe().getKeyPrefix(), dmpl__RelatedObjectId__c = Schema.Contact.SObjectType.getDescribe().getKeyPrefix() ); insert setting4; Test.startTest(); CreateRelatedResult result4 = DocumentSelectorController.releaseDocument(setting4.Id, testOrder.Id); Test.stopTest(); System.assertEquals('No handler attached', result4.Message); // 测试异常场景 Test.startTest(); try { DocumentSelectorController.releaseDocument('000000000000000AAA', testOrder.Id); System.assert(false, 'Expected exception not thrown'); } catch (Exception e) { System.assert(true); } Test.stopTest(); } static testMethod void testReleaseChildDocuments() { // 构造测试用SourceObjectInfo列表 List<SourceObjectInfo> testChildInfo = new List<SourceObjectInfo>{ new SourceObjectInfo(Id = [SELECT Id FROM dmpl__SaleOrder__c LIMIT 1].Id, Name = 'Test Line') }; // 测试SaleOrder -> InventoryFulfillment分支 dmpl__CreateRelatedSetting__mdt setting1 = [SELECT Id FROM dmpl__CreateRelatedSetting__mdt WHERE MasterLabel = 'SaleOrder to InventoryFulfillment']; dmpl__SaleOrder__c testOrder = [SELECT Id FROM dmpl__SaleOrder__c LIMIT 1]; Test.startTest(); CreateRelatedResult result1 = DocumentSelectorController.releaseChildDocuments(testOrder.Id, setting1.Id, testChildInfo); Test.stopTest(); System.assertNotEquals(null, result1); // 测试异常场景 Test.startTest(); try { DocumentSelectorController.releaseChildDocuments(testOrder.Id, '000000000000000AAA', testChildInfo); System.assert(false, 'Expected exception not thrown'); } catch (Exception e) { System.assert(true); } Test.stopTest(); } // 模拟SourceObjectInfo类(测试中需要) private class SourceObjectInfo { public Id Id { get; set; } public String Name { get; set; } } // 模拟CreateRelatedResult类(测试中需要) private class CreateRelatedResult { public String Message { get; set; } public Boolean IsSuccess { get; set; } public CreateRelatedResult(String message) { this.Message = message; this.IsSuccess = false; } } }
额外注意事项
- 如果
CreateRelatedSettingHelper等依赖类逻辑复杂,可使用Mock类(如System.StubProvider)隔离依赖,避免测试受Helper类内部逻辑影响。 - 确保所有自定义对象和元数据的API名称与生产环境一致,避免因命名错误导致测试失败。
- 针对
releaseChildDocuments的剩余分支,参照上述测试逻辑,补充对应元数据和测试用例即可覆盖。
内容的提问来源于stack exchange,提问作者Mandeep Kaur
相关产品推荐
相关产品推荐

