用途
Salesforce Apex Quality Guardrails 是一套应用于 Salesforce Apex 开发的代码质量检查规则,适用于编写或审查每一个 Apex 类、触发器和测试文件时逐项执行。
主要能力
一、治理限制安全检查
在判定任何 Apex 文件合格之前,先扫描以下模式:
- 循环中的 SOQL 与 DML——自动判定失败。
- 示例(禁止):
for (Account a : accounts) { List<Contact> contacts = [SELECT Id FROM Contact WHERE AccountId = :a.Id]; update a; } - 示例(推荐):先收集 ID 集合,
Set<Id> accountIds = new Map<Id, Account>(accounts).keySet();,对IN :accountIds做单次查询并构建Map<Id, List<Contact>>,最后在循环外执行一次update accounts; - 规则:如果在
for循环体内看到[SELECT或Database.query,以及insert、update、delete、upsert、merge等 DML,应先重构再继续。
二、共享模型验证
每个类必须显式声明共享意图,未声明会继承调用者,行为不可预测。
public with sharing class Foo:服务、处理器、选择器与控制器类的默认选择。public without sharing class Foo:仅在需要提权运行时使用(如系统级日志、触发器旁路),并需代码注释说明原因。public inherited sharing class Foo:应遵循调用者共享上下文的框架入口点。
如果类没有上述三种声明之一,应先补上声明再写其他内容。
三、CRUD / FLS 强制校验
代表用户读写记录的 Apex 代码必须验证对象和字段访问权限。平台在 Apex 中不会自动强制 FLS 或 CRUD。
- 查询字段前检查:
if (!Schema.sObjectType.Contact.fields.Email.isAccessible()) { throw new System.NoAccessException(); } - 或使用 SOQL 的
WITH USER_MODE(API 56.0+)。 - 或使用
Database.query('SELECT Id, Email FROM Contact', AccessLevel.USER_MODE)。 - 规则:任何可从 UI 组件、REST 端点或
@InvocableMethod调用的 Apex 方法必须强制 CRUD/FLS;仅从可信上下文调用的内部服务方法可使用 with sharing 替代。
四、SOQL 注入防护
- 禁止将用户输入拼接到 SOQL 字符串:
String soql = 'SELECT Id FROM Account WHERE Name = \'' + userInput + '\''; - 应使用绑定变量:
String soql = [SELECT Id FROM Account WHERE Name = :userInput]; - 动态 SOQL 且字段名受用户控制时,须用白名单校验,例如
Set<String> allowedFields = new Set<String>{'Name', 'Industry', 'AnnualRevenue'};,不在白名单内则抛出IllegalArgumentException。
五、现代 Apex 惯用法
建议采用较新的语言特性(API 62.0 / Winter '25+):
if (obj != null) { x = obj.Field__c; }→x = obj?.Field__c;x = (y != null) ? y : defaultVal;→x = y ?? defaultVal;System.assertEquals(expected, actual)→Assert.areEqual(expected, actual)System.assert(condition)→Assert.isTrue(condition)- 无共享上下文的
[SELECT ... WHERE ...]→[SELECT ... WHERE ... WITH USER_MODE]
六、PNB 测试覆盖清单
每个功能都必须覆盖三条路径,缺一即视为质量失败:
- 正向路径:预期输入到预期输出;断言具体字段值、记录数或返回值,而不只是未抛异常。
- 负向路径:无效输入、null 值、空集合和错误条件;断言抛出正确类型和消息的异常;断言操作失败时未修改任何记录。
- 批量路径:在单个测试事务中插入/更新/删除 200–251 条记录;断言全部记录正确处理,不因治理限制出现部分失败;使用
Test.startTest()/Test.stopTest()隔离异步工作的治理限制计数器。
测试类规则:使用 @isTest(SeeAllData=false)(除非有记录在案的理由才可例外);在 @TestSetup 中创建所有测试数据,若项目已有工厂则使用工厂;用 Assert.areEqual 等断言有意义的业务结果。
七、触发器架构清单
- 每个对象一个触发器;若存在第二个触发器,合并到处理器中。
- 触发器体内只包含上下文检查、处理器调用和路由逻辑。
- 触发器体内不写业务逻辑、SOQL 或 DML。
- 若项目已使用触发器框架(如 Trigger Actions Framework、ff-apex-common 或自定义基类),应扩展它,不要另建并行模式。
- 处理器类默认 with sharing,除非触发器需要提权访问。
反模式速查
- 循环内 SOQL:重构为循环前查询、基于集合操作。
- 循环内 DML:重构为先收集变更、循环后单次 DML。
- 类缺少共享声明:添加 with sharing(或说明为何 without sharing)。
- 用户数据上设置
escape="false"(Visualforce):移除,自动转义可强制 XSS 防护。 - 空 catch 块:添加日志与适当的重新抛出或错误处理。
- 字符串拼接 SOQL 且含用户输入:改用绑定变量或白名单校验。
- 无断言测试:添加有意义的
Assert.*调用。 - 使用
System.assert/System.assertEquals风格:升级为Assert.isTrue/Assert.areEqual。 - 硬编码记录 ID(如
'001...'):替换为查询或插入得到的测试记录 ID。
适用场景与限制
该技能面向 Salesforce 平台的 Apex 开发与代码审查,帮助在编码阶段拦截治理限制、权限安全、注入风险与测试覆盖类问题。资料未提供该技能的安装方式、平台依赖细节、版本兼容范围或任何收费信息,这些内容暂未提供。