[SalesForce] User created in test class isn’t returned in SOQL query

I have a test class that, as one of the steps, inserts a portal user. After that's done, I use System.RunAs to insert a case as the portal user. The insertion of the case fires a trigger that includes a step to query the user object and then loop through it until it finds the current user.

I'm expecting that query to return the current user, but it isn't. Interestingly, my debug statements indicate that the user was indeed created.

Any ideas for why my query isn't returning the user created in the test class?

Test class:

@IsTest public class Case_Partner_AccountTest { 

    public static Account getAcc(){
        Account a = new Account(Name = 'Test Account');
        insert a;
        return a;
    } 

    // Creates and returns a contact
    public static Contact getCon(){
        Contact c = new Contact(LastName = 'Testing', AccountId = getAcc().Id);
        insert c;
        return c;
}

    // Creates and returns a user with parameter specified profile
    public static User getUser(boolean hasContact, String profileName){
        Profile pr = [SELECT Id FROM Profile WHERE Name = :profileName];
        User u = new User();
        u.FirstName = 'Ivanna';
        u.LastName = 'Testmor';
        u.Email = 'itestmor@xyz123.com.testuser';   
        u.Username = 'itestmor@xyz123.com.testuser';
        u.Alias = 'itestmor';
        u.CommunityNickname = 'itestmor';
        u.TimeZoneSidKey = 'GMT';
        u.LanguageLocaleKey = 'en_US';
        u.EmailEncodingKey = 'UTF-8';
        u.LocaleSidKey = 'en_US';
        if(hasContact){
            Contact c = getCon();
            u.ContactId = c.Id;
            u.PortalRole = 'Worker';
        }
        u.ProfileId = pr.Id;
        insert u;
        return u;
}

    @IsTest public static void test01(){
        User u = getUser(true, 'Custom Portal Support User');
        Case c = new Case();
        Test.startTest();
        System.runAs(u){
            insert c;
        }
        Test.stopTest();

Here's the class that gets called from the Case trigger. You can see that is should loop through the User object and find the user. The FOR loop is failing to find the user created in the test class, even though the debug statement in line 5 shows that a user ID exists:

public class CaseTrigger_Partner_Account {
    public static void execute(List<Case> tNew, boolean tIsInsert){
        User currentUser;
        Id uId = userInfo.getUserId();
        System.debug('uId is ' + uId);
        for(User u : GlobalUtils.getUserIdMap().values()){
            if(u.Id == uId) {
                currentUser = u;
                break;
            }
        }

GlobalUtils.getUserIdMap (this is called in the class above):

private static Map<Id,User> UserIdMap;
public static Map<Id,User> getUserIdMap(){
    if(UserIdMap == NULL)
        UserIdMap = new Map<Id,User>([Select Id, Name, UserRoleId, ManagerId, UserName, usertype, ContactId, Contact.AccountId, Contact.Account.Name, FirstName, LastName, IsActive FROM User]);
    return UserIdMap;
}

Best Answer

Static variables remain set for the duration of the transaction. If your Contact trigger also makes use of GlobalUtils.getUserIdMap, then your query will get lazy loaded before you create the user. Then, when you run your Case trigger, the stale data cache is used, and your user is not found.

You could get around this by setting the map to null after, but it is private. Another workaround would be to use @TestSetup to create your data. Setup methods annotated in such a way run in a separate transaction, so you will not run into issues with static lazy loading. It would look something like:

static final String aliasWithContact = 'withCon';
static final String aliasWithoutContact = 'noCon';
// hopefully the above are unique to your org

@TestSetup
static void setup()
{
    Contact record = new Contact(/*data*/);
    insert record;
    User u1 = new User(Alias=aliasWithContact, /*add other data*/);
    User u2 = new User(Alias=aliasWithoutContact, /*add other data*/);
    insert new List<User> { u1, u2 };
}

static testmethod void testUserWithContact()
{
    system.runAs([SELECT Id FROM User WHERE Alias = :aliasWithContact])
    {
        // logic here
    }
}
static testmethod void testUserWithoutContact()
{
    system.runAs([SELECT Id FROM User WHERE Alias = :aliasWithoutContact])
    {
        // logic here
    }
}
Related Topic