Skip to content
Home » Blog » Queueable Running User in Unit Test

Queueable Running User in Unit Test

I noticed that the Running User context of a Queueable Job in a unit test depends on who calls the Test.stopTest() method. While when code is ran normally (trigger, anonymous, …) the User context of the Queueable is the same as the user who put it on the queue.

So if you use System.runAs in a unit test to queue a job, the user context of the job will be different if you call Test.stopTest() inside or outside of the System.runAs block. Basically you can produce a scenario that would never arise normally. If you don’t call Test.stopTest() at all, the job is executed at the end of the unit test, again in context of the running user of the test and not the user who queued the job.

It cost me some time debugging a failing test that used the UserInfo.getUserId() in a trigger with some dependent logic so I created a simple Queueable class to help me investigate. I might have just missed some piece of documentation, but hopefully this can save someone else some time.

public with sharing class QueueableClass implements Queueable {
    public void execute(QueueableContext context) {
        System.debug(LoggingLevel.DEBUG, 'InQueueable: ' + UserInfo.getName());
    }
}

I ran this anonymous script to confirm the normal scenario

System.debug(LoggingLevel.DEBUG, 'InAnonymousAs: ' + UserInfo.getName());
System.enqueueJob(new QueueableClass());

Then I wrote some unit tests and noted who the running user is inside the Queueable job:

@IsTest
private class QueueableTest {
    @IsTest
    static void queueableRanAsRunningUser() {
        //DEBUG|InQueueable: User User
        User newUser = getTestUser();
        System.debug(LoggingLevel.DEBUG, 'InTest: ' + UserInfo.getName());
        Test.startTest();
        System.runAs(newUser) {
            System.debug(LoggingLevel.DEBUG, 'InRunAs: ' + UserInfo.getName());
            System.enqueueJob(new QueueableClass());
        }
        Test.stopTest();
    }

    @IsTest
    static void queueableRanAsTestUser() {
        //DEBUG|InQueueable: TestUser
        User newUser = getTestUser();
        System.debug(LoggingLevel.DEBUG, 'InTest: ' + UserInfo.getName());
        System.runAs(newUser) {
            Test.startTest();
            System.debug(LoggingLevel.DEBUG, 'InRunAs: ' + UserInfo.getName());
            System.enqueueJob(new QueueableClass());
            Test.stopTest();
        }
    }

    @IsTest
    static void queueableRanAsRunningUserNoStopTest() {
        //DEBUG|InQueueable: User User
        User newUser = getTestUser();
        System.debug(LoggingLevel.DEBUG, 'InTest: ' + UserInfo.getName());
        System.runAs(newUser) {
            System.debug(LoggingLevel.DEBUG, 'InRunAs: ' + UserInfo.getName());
            System.enqueueJob(new QueueableClass());
        }
    }

    private static User getTestUser() {
        Id profileIdToUse = UserInfo.getProfileId();
        String rnd = String.valueOf((Math.random())).left(5);
        return new User(
            ProfileId = profileIdToUse,
            LastName = 'TestUser',
            Username = 'testuser' + rnd + '@invalid.test',
            Email = 'testuser@invalid.test',
            EmailEncodingKey = 'UTF-8',
            LanguageLocaleKey = 'en_US',
            TimeZoneSidKey = 'GMT',
            LocaleSidKey = 'en_US',
            Alias = 'tst',
            IsActive = true
        );
    }
}

As pointed out by Adrian Larson in my Stack Exchange question this is probably as designed. However, I still think it’s not intuitive and does not follow what productive code would do.

Other Traps

UoW and SObject Instances

Oct 28, 202314 min read

Remember that SObjects passed as arguments in Apex point to the same instance, even into the UoW. If you change your variable after registering it as dirty you may affect what gets committed in the end.

LWC in Purgatory

Jun 12, 202402 min read

You cannot easily move LWC Component Bundles which call Apex between Unlocked Packages with Namespace

0 0 votes
Article Rating
Subscribe
Notify of
guest
0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x