Search code examples
unit-testingsalesforceapex-code

How to avoid MIXED_DML_OPERATION error in Salesforce tests that create Users


Sometimes in Salesforce tests you need to create User objects to run part of the test as a speciifc type of user.

However since the Salesforce Summer 08 update, attempts to create both User objects and normal objects (such as Accounts) in the same test lead to the following error:

MIXED_DML_OPERATION, DML operation on setup object is not permitted after you have updated a non-setup object (or vice versa): User, original object: Account

Note that the error doesn't happen when you run the tests from Eclipse/Force.com IDE, but it does happen when you deploy to Salesforce and then run the tests from within Salesforce.

How do I re-write my tests to avoid this error?

Here's a simple example of a test that causes the error:

static testMethod void test_mixed_dmlbug() {        
    Profile p = [select id from profile where name='(some profile)'];
    UserRole r = [Select id from userrole where name='(some role)'];
    User u = new User(alias = 'standt', email='standarduser@testorg.com', 
            emailencodingkey='UTF-8', lastname='Testing', 
            languagelocalekey='en_US', 
            localesidkey='en_US', profileid = p.Id, userroleid = r.Id,
            timezonesidkey='America/Los_Angeles', 
            username='standarduser@testorg.com');
    Account a = new Account(Firstname='Terry', Lastname='Testperson');
    insert a;

    System.runAs(u) {
        a.PersonEmail = 'test@madeupaddress.com';
        update a;
    }

}

Solution

  • Not many Salesforce people on here yet, I guess.

    I found a solution, I don't know why it works, but it works.

    All parts of the test that access normal objects need to be wrapped in a System.runAs that explicitly uses the current user, like this:

    User thisUser = [ select Id from User where Id = :UserInfo.getUserId() ];
    System.runAs ( thisUser ) {
        // put test setup code in here
    }
    

    So, the example text_mixed_dmlbug method given in the question, would become:

    static testMethod void test_mixed_dmlbug() {  
        User u;
        Account a;      
        User thisUser = [ select Id from User where Id = :UserInfo.getUserId() ];
        System.runAs ( thisUser ) {
            Profile p = [select id from profile where name='(some profile)'];
            UserRole r = [Select id from userrole where name='(some role)'];
            u = new User(alias = 'standt', email='standarduser@testorg.com', 
                emailencodingkey='UTF-8', lastname='Testing', 
                languagelocalekey='en_US', 
                localesidkey='en_US', profileid = p.Id, userroleid = r.Id,
                timezonesidkey='America/Los_Angeles', 
                username='standarduser@testorg.com');
            a = new Account(Firstname='Terry', Lastname='Testperson');
            insert a;
        }
        System.runAs(u) {
            a.PersonEmail = 'test@madeupaddress.com';
            update a;
        }
    
    }
    

    Then the MIXED_DML_OPERATION errors stop happening.