While writing an apex test case I noticed a strange behavior with System.runAs(). My tests were failing incorrectly, because system.runAs() was somehow not resetting the CRUD/FLS context for different profiles across same or different test method executions.
Here is the complete Test class with all comments and required code. To test it one can deploy this to their DE org directly, it has no dependencies.
@isTest
private class Test_System_RunAs {
/*
This test class has two test methods, i.e.
1. testWithSysAdmin() executes a FLS check with SYS Admin profile
2. testWithChatterFree() executes a FLS check with Chatter Free profile
PROBLEM :
Both of these methods doesn't execute correctly.
The one that executes first sets the profile context via System.runAs()
and somehow its not reset internally for the second testMethod execution,
this makes the testMethod executing later fail (as profile permissions mismatch)
Though if we comment and execute both these testMethods one at a time, they will behave correct.
So that means each of these testXXX() methods are correct, somehow context is not reset correctly
when they execute one after another.
QUESTION :
Am I doing something wrong or is this some bug in System.runAs() context, I feel it takes care
of sharing rules etc, but doesn't enforces the FLS correctly ?
*/
public static testMethod void testWithSysAdmin() {
System.runAs(createMockUserForProfile('System Administrator')) {
// This debug indicates different profiles
System.debug('ProfileId:' +Userinfo.getProfileId());
System.assertEquals(true, Account.BillingCity.getDescribe().isUpdateable());
}
}
public static testMethod void testWithChatterFree() {
System.runAs(createMockUserForUserLicense('Chatter Free')) {
// This debug indicates different profiles
System.debug('ProfileId:' +Userinfo.getProfileId());
// Chatter Free user has no permission on the Account, so it should be false
System.assertEquals(false, Account.BillingCity.getDescribe().isUpdateable());
}
}
static User createMockUserForUserLicense(String licenseName) {
Profile p = [SELECT Id FROM profile WHERE UserLicense.Name like :licenseName LIMIT 1];
return createMockUser(p.id);
}
static User createMockUserForProfile(String profileName) {
Profile p = [SELECT Id FROM profile WHERE name like :profileName];
return createMockUser(p.id);
}
static User createMockUser(Id profileId) {
User u = new User(alias = 'newUser', email='newuser@tgerm.com.test',
emailencodingkey='UTF-8', lastname='Testing',
languagelocalekey='en_US', localesidkey='en_US', profileid = profileId,
timezonesidkey='America/Los_Angeles', username= System.now().millisecond() + 'newuser@tgerm.com.test');
insert u;
return u;
}
}
Your views and comments
Looking forward for your views on this. But this seems to be a bug in System.runAs() implementation, what do you say ?
Posted the same as a question on Apex development boards here
Comments (6)
Anonymoussays:
September 24, 2011 at 4:22 pmSystem.runAs does not affect CRUD/FLS. From the documentation (http://developer.force.com/cookbook/recipe/using-system-runas-in-test-methods)”Only the following items use the permissions granted by the user specified with runAs:* dynamic apex* methods using with sharing or without sharing* shared records”
Anonymoussays:
September 24, 2011 at 4:27 pmI agree @richunger, System.runAs() official docs doesn't have explicit mention about CRUD/FLS enforcement. But as mentioned in post above, if only one test method with CRUD/FLS based test is executed it works fine, that means the CRUD/FLS is also enforced. But it doesn't gets reset to original or new context, in next System.runAs() call.
Anonymoussays:
September 24, 2011 at 4:44 pmAh, I see what you mean. Yes, this is a bug. There's caching happening there which should be invalidated.
Anonymoussays:
September 24, 2011 at 4:48 pmYes this is a corner case, most of the test cases in Apex are around data and sharing stuff. Its my tough day today, that I stumbled upon such a buggy use case đŸ™‚
Anonymoussays:
February 18, 2012 at 6:26 pmThanks for posting this. I was surprised when I found that System.runAs doesn't enforce object write permissions. I wasn't able to write a test to ensure that a profile can't create an object.Very strange limitation of System.runAs.
Anonymoussays:
February 18, 2012 at 7:56 pmWelcome Alex, we're lucky to have Rich Unger here discussing this issue. Seems its some bug to be resolved soon.