+ Start a Discussion
Scott.MScott.M 

DML not allowed on user in test context

Hi,

Here's my situation. I'm working on an application in a developer organization. I've created an extra user for the end user of the application I've created so I can get feedback from the end user as I'm developing the application. I would like to write test cases with users that are created with DML as was recommend and demoed at dreamforce. The problem is that the developer organization has a limit of 2 user licenses. That's fine, so I thought I'll just delete the users in the test method and create new generic ones and at the end of the tests everything would roll back. Unfortunately I received the error that DML is not allowed on the user object. Is there anyway around this?

Thanks!
Scott
Best Answer chosen by Admin (Salesforce Developers) 
philbophilbo
Hey,

There are ways to alleviate your pain:

1) When creating test Users, set their IsActive flag to False.  They'll still work fine for most purposes, and won't cause issues with your org's licensing limits.

2) When doing 'setup-object DML' in your test methods, such as creating test Users or Groups, wrap the DML statements as follows:

User thisUser = [ select Id from User where Id = :UserInfo.getUserId() ];
System.runAs ( thisUser ) {
    ...your setup-object DML...
}


You can then put regular DML in the same method, outside of the above block, and everything coexists nicely.  I believe for this to work, the API version of your test class must be at least 13.0.



Message Edited by philbo on 11-19-2008 03:25 PM

All Answers

RickyGRickyG
Scott -

The new Developer Edition org only allows for 2 Salesforce licenses - you also have 3 Platform licenses, which you assign by using the appropriate profile. 

Not sure if this solution alone will address your situation.  I know that you cannot have 'mixed' DML in the same transaction, meaning that you cannot write to a 'setup object' (like User) in the same transaction that you write to a non-setup object, like any custom object. 

You can see an example of how to create users in the InitUsers class for the Developer Guide book, which can be loaded with Force.com Migration Tool scripts as described on a number of pages beginning here.

Hope this helps.
philbophilbo
Hey,

There are ways to alleviate your pain:

1) When creating test Users, set their IsActive flag to False.  They'll still work fine for most purposes, and won't cause issues with your org's licensing limits.

2) When doing 'setup-object DML' in your test methods, such as creating test Users or Groups, wrap the DML statements as follows:

User thisUser = [ select Id from User where Id = :UserInfo.getUserId() ];
System.runAs ( thisUser ) {
    ...your setup-object DML...
}


You can then put regular DML in the same method, outside of the above block, and everything coexists nicely.  I believe for this to work, the API version of your test class must be at least 13.0.



Message Edited by philbo on 11-19-2008 03:25 PM
This was selected as the best answer
RickyGRickyG
Phil -

Great answers!
osamanosaman

There is a work around for that.

If you want to perform two DML operations sequentially, create a seprate method for 2nd DML operation with @future token.

make sure you put System.RunAs() in the method. Your overall method should look like this

 

private static void myFunc()

{

     ///1st DML operation

 

     User usr = [Select id from User where Id = :UserInfo.getUserId()];

 

     System.RunAs(usr)

     {

        Test.startTest();

         myFunc2();

         Test.stopTest();

     }

 

 

}

 

@future

private static void myFunc2()

{

   ///2nd DML operation

}

sam_matsam_mat

Thanks for solution.

Salesforce SamuraiSalesforce Samurai

I am running into the same DML errors while trying to upload a new package (it deployed fine). 

 

I put this fix in, but I am still getting the same error:

 

System.DmlException: Insert failed. First exception on row 0; first error: MIXED_DML_OPERATION, DML operation on setup object is not permitted after you have updated a non-setup object (or vice versa): Lead, original object: QueueSobject: []

 

Does this look like the correct way to implement this workaround?  (sorry, not the strongest developer... learning :))

 

static testMethod void myTest1() {

        // This code runs as the system user

        User u1;
        User thisUser = [ select Id from User where Id = :UserInfo.getUserId() ];
        System.runAs ( thisUser )
        {
        
        try{
          u1 = [select Id from User WHERE IsActive=True AND Profile.Name = 'System Administrator'  LIMIT 1];
        } catch (QueryException qe){

        List<User> users = [SELECT Id, Profile.PermissionsModifyAllData FROM User WHERE IsActive = true LIMIT 1000];

        for(User u : users){
            if(u.Profile.PermissionsModifyAllData = true){
              u1 = u;
              break;
        }
        }  
        }
        }

 

Thank you!

seshu paturuseshu paturu
What if I don't want to use SOQL in Test classes??
Narasimha Reddy 69Narasimha Reddy 69
if we execute following code as below 
public class DML_On_sycToAsy {
public static void myFunc()
{
     ///1st DML operation
      User usr = [Select id from User where Id = :UserInfo.getUserId()];
      System.RunAs(usr)
     {
        Test.startTest();
         myFunc2();
         Test.stopTest();
     }
 
 
}
 
@future
private static void myFunc2()
{
    //2nd DML operation
 list<Emp__c> emp = [select name from Emp__c] ;
   system.debug('employee...'+emp.size());
     
}
}
will get an error message as "Static method cannot be referenced from a non static context:"