3

I have written a pretty simple VF page that allows support users to add Case Assists (custom object related to Case) to their case. Pretty simple VF page, when opened, it creates a list of a wrapper class I created for users with a particular profile. Pretty simple SOQL query to grab all those users, and create wrapper objects off of them. After implemented, it seemed the support management team, was wanting to add and remove people outside of the support team at a somewhat often basis. This was a pain as I had hardcoded the SOQL query to look at the certain profile of the users. To solve this I created a custom setting that had a text field that held the user ID's of anyone to include in my SOQL query. This made it much easier as I could have an admin add and remove these people quickly without any coding changes.

Here are the pertinent pieces of my controller code

public with sharing class AddCaseAssistsController {

        private Case myCase;
        public list<userWrapper> uWraps         {get;set;}
        public boolean notTheOwner               {get;set;}

        public AddCaseAssistsController(ApexPages.StandardController stdController) {

            this.myCase = (Case)stdController.getRecord();
            myCase = [Select Id, CaseNumber, OwnerId From Case Where Id =: myCase.Id];

            uWraps = new list<userWrapper>();

            Support_Configuration__c supportConfig = Support_Configuration__c.getInstance();
            string userString = (supportConfig.Users_outside_of_support_for_assists__c == null) ? '' : supportConfig.Users_outside_of_support_for_assists__c;
            set<String> userIDs = new set<String>();
            userIDs.addAll(userString.split(';'));


            list<User> users = [Select Id, Name, FirstName, LastName 
                                From User 
                                Where isActive = true and (Id In: userIDs Or (Profile.Name = 'Imprivata Support' And Id !=: UserInfo.getUserId()))
                                Order By LastName, FirstName];

            for(User u : users){
                uWraps.add(new userWrapper(u, false));
            }

            notTheOwner = (myCase.OwnerId != UserInfo.getUserId()) ? true : false;

        }
}

This works fine and I can test it any which way in the UI and it works fine. The issue I am running into is when I write my test class. It seems that if I run my test method as myself (or just as the logged in user) it works fine and passes. The minute I try to use the RunAs() function in the test method, it fails and doesn't include any of the people whose IDs are listed in the custom setting.

Below works, but the minute I uncomment out the RUNAS() statement, it fails the assertion that the usermap includes the nonsupport user that is in the custom setting. The line below is what is failing, but only when i use the RunAs()

system.assertEquals(true, supportUserMap.containsKey(String.valueOf(nonSupportUser.Id)));

@isTest
private class AddCaseAssistsControllerTest {

    private static final Account acc = TestClassObjectUtility2.accountCreator('Test Account');
    private static final Contact con = TestClassObjectUtility2.contactCreator(acc.Id, 'Joe', 'Shmoe');
    public static final Id SupportCaseRT = Schema.SObjectType.Case.getRecordTypeInfosByName().get('Support Case').getRecordTypeId();
    public static final User supportCaseOwnerUser;
    public static final User supportNonCaseOwnerUser;
    public static final User nonSupportUser;
    public static Case myCase;
    public static final PageReference pg = Page.AddCaseAssists;
    public static ApexPages.StandardController stanCont;

    static{ 

        supportCaseOwnerUser = [Select Id, Name From User Where isActive = true And Profile.Name = 'Imprivata Support' limit 1];
        supportNonCaseOwnerUser = [Select Id, Name From User Where isActive = true And Profile.Name = 'Imprivata Support' And Id !=: supportCaseOwnerUser.Id limit 1];
        nonSupportUser = [Select Id, Name From User Where isActive = true And Profile.Name = 'Imprivata Sales Rep User' limit 1];

    }

    public static testmethod void NonSupportUserTest() {

            Support_Configuration__c supportConfig = Support_Configuration__c.getInstance();
            system.debug('Custom Setting Before: ' + supportConfig);
            supportConfig.Users_outside_of_support_for_assists__c = String.valueOf(nonSupportUser.Id);
            upsert supportConfig;

            myCase = TestClassObjectUtility2.CaseCreator(true, supportCaseOwnerUser.Id, acc.Id, con.Id, 'Email', 'New');
            stanCont = new ApexPages.standardController(myCase);

            //system.runAs(supportNonCaseOwnerUser){  **Uncommenting this makes it fail**
                Test.setCurrentPage(pg);
                AddCaseAssistsController controller = new AddCaseAssistsController(stanCont);

                Case c = controller.getCase();

                system.assertEquals(c.Id, myCase.Id);

                map<Id,User> supportUserMap = new map<Id,User>();
                for(AddCaseAssistsController.userWrapper uWrap : controller.uWraps){
                    supportUserMap.put(uwrap.u.Id, uWrap.u);
                }

                system.assertEquals(true, supportUserMap.containsKey(supportNonCaseOwnerUser.Id));
                system.assertEquals(true, supportUserMap.containsKey(supportCaseOwnerUser.Id));
                system.assertEquals(true, supportUserMap.containsKey(String.valueOf(nonSupportUser.Id)));
                system.assertEquals(true, supportUserMap.containsKey(c.OwnerId));
                system.assertEquals(true, controller.notTheOwner);
            //}

        }
}

This isn't necessarily a blocker as I can test this in the UI, logged in as any user and it works fine. I have used debug statement and the custom setting does get updated and include the user id, it just is not working when I use the RunAs() statement. This must be something to do with RunAS() and test methods specifically, I just can't find any documentation or blogs, or older posts that can answer why this is happening.

Any help or insight would be greatly appreciated.

6
  • How do you mock supportNonCaseOwnerUser? How do you mock nonSupportUser ? Support_Configuration__c is a hierarchical custom setting and you refer to the value using the runAs user's value in the code under test but perhaps the mocking is establishing the value at some other level. Usually, I mock hierarchical custom settings at the same level as the runAs user
    – cropredy
    Jan 15, 2015 at 17:54
  • The hierarchical Custom setting is set at the default org level, so I don't believe it would matter who I am running as, since it will always default to the default org level. To answer the question though, I am simply setting the users using a SOQL query as User data is available in testing context Jan 15, 2015 at 18:03
  • just for grins, if you tried seeAlldata=true and removed the mocking of the custom setting, does the test method pass with the runAs? I'm not suggesting that as a permanent fix but more as a diagnostic aid
    – cropredy
    Jan 15, 2015 at 18:12
  • I thought that same thing as I read that seeAlldata=True sometimes solves these custom setting issues, but it didn't have any effect. I was a bit releived that it didn't solve it though, as I really would not want that as an alternative. Good idea, and thanks for the help though. Jan 15, 2015 at 18:23
  • are your mocked test users active? sometimes I forget to query for isActive = true
    – cropredy
    Jan 15, 2015 at 18:33

1 Answer 1

3

Could you try using getOrgDefaults() instead of getInstance()? I wonder if there is something weird where it may be applying the Custom Setting to your ID when you do the upsert instead of the OrgDefault?

Support_Configuration__c supportConfig = Support_Configuration__c.getOrgDefaults();
system.debug('Custom Setting Before: ' + supportConfig);
supportConfig.Users_outside_of_support_for_assists__c = String.valueOf(nonSupportUser.Id);
upsert supportConfig;

Just a stab in the dark.

4
  • Wow. I swear to go, somewhere along the line I used getOrgDefaults() and I thought it made no difference, but that fixed it. That is extremely odd. getInstance() supposedly gets the lowest level defined in the hierarchy, so when all I define is the org defaults, that is the lowest level. Is this a bug? Or am I just misinterpreting something? Either way, thanks for this. Jan 16, 2015 at 14:21
  • It could be a bug, at least that's what I would think. What made me think of that is that the custom setting documentation explains that getInstance() gets the current user (the lowest level) but if there is no definition at that level, it gets populated with the next level up. I wonder if it is still populating the SetupUserId the ID of the running user. Jan 16, 2015 at 14:29
  • So that made me start thinking. When I used some debug statements, when I used getInstance(), the SetupUserId was me, as I was running this outside of the runAs() block. On a hunch I moved the custom setting block of code within the runAs() statement, and it then worked with getInstance(). So I think it had to do with running the getInstance() method using a different user then was trying to access the results of it. Very interesting. I don't know if this is a bug or just a caveat that isn't well documented. Interested to see if anyone has noticed this before. Jan 16, 2015 at 14:47
  • Its not a bug. As per Salesforce documentation, getInstance method always returns the instance of current user; hence the setupOwnerId returns the running users Id. It then checks if there are user level settings for user. If no, it fetches the details from the profile level or organisation level and merges the blank fields. salesforce.com/us/developer/docs/dbcom_apex290/Content/…
    – RajeshShah
    May 18, 2015 at 9:47

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .