Apex测试创建测试User触发MIXED_DML_OPERATION错误的问询
MIXED_DML_OPERATION错误的原因及解决方法
错误原因
Salesforce将对象分为两类:设置对象和非设置对象:
- 设置对象(如User、Profile、Role)用于组织级配置,操作会影响整个Salesforce环境的规则和权限;
- 非设置对象(如Account、Contact、Opportunity)是业务数据载体,仅涉及具体业务记录。
为了避免配置操作与业务数据操作互相干扰、保证事务原子性和数据一致性,Salesforce禁止在同一个事务内混合执行两类对象的DML操作。你的代码先插入了非设置对象(Account),接着在同一事务中插入设置对象(User),触发了这个限制。
解决方法
1. 使用System.runAs()隔离事务
System.runAs()会创建一个独立的事务上下文,在这个上下文中执行设置对象的DML操作,就能和之前的非设置对象操作隔离。
示例代码:
@isTest private class MyTestClass { @isTest static void testUserCreation() { // 先创建非设置对象(Account、Contact) Account testAcc = new Account(Name='Test Account'); insert testAcc; Contact testCon = new Contact(LastName='Test', AccountId=testAcc.Id); insert testCon; // 通过System.runAs开启新事务,创建User System.runAs(new User(Id=UserInfo.getUserId())) { Profile standardProfile = [SELECT Id FROM Profile WHERE Name='Standard User']; User testUser = new User( FirstName='Demo', LastName='User', Username='demo_user_' + System.currentTimeMillis() + '@test.com', Email='demo@test.com', Alias='demousr', ProfileId=standardProfile.Id, TimeZoneSidKey='America/Los_Angeles', LocaleSidKey='en_US', EmailEncodingKey='UTF-8', LanguageLocaleKey='en_US', CommunityNickname='demousr' ); insert testUser; // 后续测试逻辑(如关联查询、业务操作) // ... } } }
2. 调整操作顺序(适用于无需提前创建业务对象的场景)
如果业务逻辑允许,可以先在主事务中创建设置对象(User),再创建关联的非设置对象(Account、Contact),这样避免跨类别DML混合:
@isTest private class MyTestClass { @isTest static void testUserAssociation() { // 先创建设置对象(User) Profile standardProfile = [SELECT Id FROM Profile WHERE Name='Standard User']; User testUser = new User( FirstName='Demo', LastName='User', Username='demo_user_' + System.currentTimeMillis() + '@test.com', Email='demo@test.com', Alias='demousr', ProfileId=standardProfile.Id, TimeZoneSidKey='America/Los_Angeles', LocaleSidKey='en_US', EmailEncodingKey='UTF-8', LanguageLocaleKey='en_US', CommunityNickname='demousr' ); insert testUser; // 再创建关联的非设置对象 Account testAcc = new Account(Name='Test Account', OwnerId=testUser.Id); insert testAcc; Contact testCon = new Contact(LastName='Test', AccountId=testAcc.Id, OwnerId=testUser.Id); insert testCon; // 后续测试逻辑 // ... } }
3. 拆分@testSetup与测试方法
如果使用@testSetup准备测试数据,要确保该方法内只执行同一类对象的DML:
- 若
@testSetup中创建设置对象,测试方法内再创建非设置对象; - 若
@testSetup中创建非设置对象,测试方法内通过System.runAs()创建设置对象。
内容的提问来源于stack exchange,提问作者I am not Fat
相关产品推荐
相关产品推荐

