Mixed DML Operations in Test Methods

Test methods allow for performing mixed Data Manipulation Language (DML) operations that include both setup sObjects and other sObjects if the code that performs the DML operations is enclosed within System.runAs method blocks. You can also perform DML in an asynchronous job that your test method calls. These techniques enable you, for example, to create a user with a role and other sObjects in the same test.

The setup sObjects are listed in sObjects That Cannot Be Used Together in DML Operations.

Because validation for mixed DML operations is skipped during deployment, there can be a difference in the number of test failures when tests are deployed versus when run in the user interface.

Note

Example: Mixed DML Operations in System.runAs Blocks

This example shows how to enclose mixed DML operations within System.runAs blocks to avoid the mixed DML error. The System.runAs block runs in the current user’s context. It creates a test user with a role and a test account, which is a mixed DML operation.
1@IsTest
2private with sharing class MixedDML {
3    @IsTest
4    static void mixedDMLExample() {  
5        User thisUser = [SELECT Id FROM User WHERE Id = :UserInfo.getUserId() WITH SYSTEM_MODE];
6       // Insert account as current user
7        System.runAs (thisUser) {
8            Profile p = [SELECT Id FROM Profile WHERE Name='Standard User' WITH SYSTEM_MODE];
9            UserRole r = [SELECT Id FROM UserRole WHERE Name='COO' WITH SYSTEM_MODE];
10            User u = new User(alias = 'jsmith', email='jsmith@acme.com', 
11                emailencodingkey='UTF-8', lastname='Smith', 
12                languagelocalekey='en_US', 
13                localesidkey='en_US', profileid = p.Id, userroleid = r.Id,
14                timezonesidkey='America/Los_Angeles', 
15                username='jsmith@acme.com');
16            insert as system u;
17            Account a = new Account(name='Acme');
18            insert as system a;
19        }
20    }
21}

Use @Future to Bypass the Mixed DML Error in a Test Method

Mixed DML operations within a single transaction aren’t allowed. You can’t perform DML on a setup sObject and another sObject in the same transaction. However, you can perform one type of DML as part of an asynchronous job and the others in other asynchronous jobs or in the original transaction. This class contains an @future method to be called by the class in the subsequent example.
1public with sharing class InsertFutureUser {
2    @Future
3    public static void insertUser() {
4        Profile p = [SELECT Id FROM Profile WHERE Name='Standard User' WITH SYSTEM_MODE];
5        UserRole r = [SELECT Id FROM UserRole WHERE Name='COO' WITH SYSTEM_MODE];
6        User futureUser = new User(firstname = 'Future', lastname = 'User',
7            alias = 'future', defaultgroupnotificationfrequency = 'N',
8            digestfrequency = 'N', email = 'test@test.org',
9            emailencodingkey = 'UTF-8', languagelocalekey='en_US', 
10            localesidkey='en_US', profileid = p.Id, 
11            timezonesidkey = 'America/Los_Angeles',
12            username = 'futureuser@test.org',
13            userpermissionsmarketinguser = false,
14            userpermissionsofflineuser = false, userroleid = r.Id);
15        insert as system futureUser;
16    }
17}
This class calls the method in the previous class.
1@IsTest
2public with sharing class UserAndContactTest {
3    public @IsTest
4    static void testUserAndContact() {
5        InsertFutureUser.insertUser();
6        Contact currentContact = new Contact(
7            firstName = String.valueOf(System.currentTimeMillis()),
8            lastName = 'Contact');
9        insert as user currentContact;
10    }
11}