测试SobjectByParams类遇异常,测试覆盖率未达标
Apex测试异常与覆盖率不足问题解决
问题描述
测试执行时抛出异常 SobjectByParams.InvalidTypeNameException: invalidSobjectNameError,且当前测试覆盖率仅53.33%,无法满足最低80%的要求。
原代码
主类 SobjectByParams
public with sharing class SobjectByParams { public SObject createSObject(String sObjectName, Map<String, String> fields) { String invalidSObjectError = System.Label.invalid_Sobject_Name; String invalidFieldError = System.Label.Invalid_Sobject_Field; SObject newObject; try { newObject = (SObject) Type.forName(sObjectName).newInstance(); } catch (NullPointerException ex) { throw new InvalidTypeNameException(invalidSObjectError); } for (String field : fields.keySet()) { try { newObject.put(field, fields.get(field)); } catch (SObjectException ex) { throw new InvalidTypeNameException(invalidFieldError); } } insert newObject; return newObject; } public class InvalidTypeNameException extends Exception { } }
测试类 SobjectByParamsTest
@IsTest public with sharing class SobjectByParamsTest { SobjectByParams sobjectByParams; private static final String TestName = 'TestName'; private static final String BCity = 'Lviv'; private static final String LastName = 'Kapo'; private static final String Email = 'email'; @IsTest static void createSObject() { SobjectByParams sobjectByParams = new SobjectByParams(); Map<String, String> fields = new Map<String, String>(); fields.put('BillingCity', BCity); Test.startTest(); SObject result = sobjectByParams.createSObject(TestName, fields); Test.stopTest(); System.assertEquals(BCity, result.get(BCity)); } }
问题分析
- 测试异常原因:测试中使用
'TestName'作为对象名称,这不是Salesforce中存在的标准或自定义对象API名称,Type.forName(sObjectName)返回null,触发NullPointerException,进而抛出自定义异常。 - 覆盖率不足原因:当前测试仅覆盖了正常创建对象的分支,未覆盖无效对象名、无效字段名这两个异常分支,导致大量代码未被执行。
解决方案
修改测试类,使用真实存在的对象(如标准对象Account),并添加异常场景测试,覆盖所有代码路径:
修改后的测试类
@IsTest public with sharing class SobjectByParamsTest { private static final String ACCOUNT_OBJECT_NAME = 'Account'; private static final String INVALID_OBJECT_NAME = 'TestName'; private static final String BILLING_CITY_FIELD = 'BillingCity'; private static final String BILLING_CITY_VALUE = 'Lviv'; private static final String INVALID_FIELD_NAME = 'Invalid_Field__c'; @IsTest static void createValidSObject_Success() { SobjectByParams sobjectByParams = new SobjectByParams(); Map<String, String> fields = new Map<String, String>(); fields.put(BILLING_CITY_FIELD, BILLING_CITY_VALUE); Test.startTest(); SObject result = sobjectByParams.createSObject(ACCOUNT_OBJECT_NAME, fields); Test.stopTest(); // 修正断言:用字段名而非字段值获取字段内容 System.assertEquals(BILLING_CITY_VALUE, result.get(BILLING_CITY_FIELD)); } @IsTest static void createSObject_InvalidObjectName_ThrowsException() { SobjectByParams sobjectByParams = new SobjectByParams(); Map<String, String> fields = new Map<String, String>(); Test.startTest(); try { sobjectByParams.createSObject(INVALID_OBJECT_NAME, fields); System.assert(false, '预期抛出InvalidTypeNameException,但未抛出'); } catch (SobjectByParams.InvalidTypeNameException ex) { System.assertEquals(System.Label.invalid_Sobject_Name, ex.getMessage()); } Test.stopTest(); } @IsTest static void createSObject_InvalidFieldName_ThrowsException() { SobjectByParams sobjectByParams = new SobjectByParams(); Map<String, String> fields = new Map<String, String>(); fields.put(INVALID_FIELD_NAME, 'test'); Test.startTest(); try { sobjectByParams.createSObject(ACCOUNT_OBJECT_NAME, fields); System.assert(false, '预期抛出InvalidTypeNameException,但未抛出'); } catch (SobjectByParams.InvalidTypeNameException ex) { System.assertEquals(System.Label.Invalid_Sobject_Field, ex.getMessage()); } Test.stopTest(); } }
修改说明
- 替换无效对象名为标准对象
Account,确保Type.forName能正常实例化对象 - 添加两个异常测试方法,分别验证无效对象名和无效字段名场景下的异常抛出逻辑
- 修正原测试中的断言错误:原代码用字段值
BCity作为键获取字段,应改为用字段名BillingCity - 所有分支逻辑均被覆盖,测试覆盖率将提升至100%
内容的提问来源于stack exchange,提问作者Pavlo Fedyk
相关产品推荐
相关产品推荐

