[SalesForce] Running user in future method while running tests

I have a Visualforce page with a custom controller. When clicking one of the buttons, code is being executed and at the end a future method is being called.

public static void clickButton() 
{ 
    //Execute code 
    //Call future method 
}

The logic of the future method contains an insert of a record. Before inserting the record, the FLS of the populated fields is being checked.

The code itself is working fine, but the test code is indicating the user doesn't have access to a field on the record that should be inserted.

In my test code I am creating a user and I assign a permission set to give the user access to the object and the necessary fields. This user is being passed to System.runAs in the tests, so the tests should be run in the context of this user.

I have been debugging the code and it appears the code before the future method is ran in the context of the created user and the logic of the future method is ran as the user who started the test. In this case the user who started the test, doesn't have access to the field. That's why the test fails.

I can solve the failing test easily, but I am wondering about the behaviour during the tests. Is it normal that the synchronous code is being executed as the created user and the asynchronous code as the user who started the test?

Thanks in advance

Edit: the test code has the below structure.

Test.startTest();
System.runAs(crmUser)
{
    PageReference pageRef = Page.page1;
    Test.setCurrentPageReference(pageRef);

    //Init the controller
    PageController myPageController = new PageController();   

    //This method is being executed when the button is clicked.
    //The future call is being done inside this method.     
    myPageController.registerUser();
}
Test.stopTest();

Best Answer

Using the @future annotation to identify methods that are executed asynchronously. When you specify future, the method executes when Salesforce has available resources.

You need to know this things here.

  • Methods with the future annotation must be static methods, and can only return a void type.

  • Asynchronous calls, such as @future or executeBatch, called in a startTest, stopTest block, do not count against your limits for the number of queued jobs.

  • Use Test.startTest & Test.stopTest around your future method call. stopTest will ensure your future method was called.

Change as below code

System.runAs(crmUser)
{
    PageReference pageRef = Page.page1;
    Test.setCurrentPageReference(pageRef);

    //Init the controller
    PageController myPageController = new PageController();   

    //This method is being executed when the button is clicked.
    //The future call is being done inside this method.     
    Test.startTest(); 
    myPageController.registerUser();
    Test.stopTest();
}
Related Topic