Understanding the Mixed DML Error
The Mixed DML error occurs when performing DML operations on both setup objects (like User, Profile, Permission Set) and non-setup objects (like Account, Contact) in the same transaction. This restriction exists because setup objects affect user access within Salesforce.
Causes of the Mixed DML Error
-
Creating or updating both a User object and standard objects (like Account, Contact) in the same test method.
-
Modifying setup objects like UserRole, Profile, or PermissionSet alongside standard objects.
-
Using automation that affects both types of objects in a single transaction.
-
Working with custom settings (which are setup objects) and standard records in the same execution context.
How to Handle the Mixed DML Error
Method 1: Use System.runAs() Blocks
apex@isTest static void testMethod1() { // Create standard objects first Account acc = new Account(Name = 'Test Account'); insert acc; // Then use runAs for setup objects System.runAs(new User(Id = UserInfo.getUserId())) { Profile p = [SELECT Id FROM Profile WHERE Name = 'Standard User']; User testUser = new User(/* User fields here */); insert testUser; } }
Method 2: Use @future Methods
apex@future public static void createTestUser() { Profile p = [SELECT Id FROM Profile WHERE Name = 'Standard User']; User testUser = new User(/* User fields here */); insert testUser; } @isTest static void testMethod1() { // Create standard objects Account acc = new Account(Name = 'Test Account'); insert acc; // Call the future method Test.startTest(); createTestUser(); Test.stopTest(); // Ensures future method executes }
Method 3: Separate Transactions with Test.startTest() and Test.stopTest()
apex@isTest static void testMethod1() { // Setup objects first Profile p = [SELECT Id FROM Profile WHERE Name = 'Standard User']; User testUser = new User(/* User fields here */); insert testUser; Test.startTest(); // Non-setup objects in a separate transaction Account acc = new Account(Name = 'Test Account'); insert acc; Test.stopTest(); }
Conclusion
Mixed DML errors can be frustrating but are easily resolved with proper test class design. The most reliable approaches are using System.runAs() blocks, @future methods with Test.startTest()/Test.stopTest(), or organizing your code to handle setup and non-setup objects in separate transactions.
Remember that the goal is to separate operations on setup objects from operations on non-setup objects to maintain data integrity and proper access permissions within Salesforce.