You need to sign in to do that
Don't have an account?
Phil W
Unfortunately it seems that both of the batches still get run with the same user (the actual user running the test rather than either of the fake users). I suspect this is because of the way batches are actually executed during the Test.stopTest method invocation, rather than at some asynchronous time.
Have I come across a bug in the way batches are run in a given user context during testing? Is there a workaround I can use?
How to run two batches from same test start/stop with different users?
I have a batch process that prevents two different "concurrent" executions of the batch for a given user by maintaining some state (in the databse) that is set in start and cleared in finish (actually using the user for the created AsyncApexJob instances). During start processing, the state is queried from the database; if there is an entry already for the current user the batch is aborted, using System.abortJob, and an empty query locator is returned.
I am trying to test that two different users can successfully execute the batch via the use of the following:
Id profileId = UserInfo.getProfileId(); List<User> fakeUsers = new List<User> { new User(Alias = 'X', Email='X@testorg.com', EmailEncodingKey='UTF-8', FirstName = 'Jim', LastName='Testing', LanguageLocaleKey='en_US', LocaleSidKey='en_US', ProfileId = profileId, TimeZoneSidKey='Europe/London', UserName='X@testorg.com'), new User(Alias = 'Y', Email='Y@testorg.com', EmailEncodingKey='UTF-8', FirstName = 'Fred', LastName='Testing', LanguageLocaleKey='en_US', LocaleSidKey='en_US', ProfileId = profileId, TimeZoneSidKey='Europe/London', UserName='Y@testorg.com') }; Test.startTest(); // Simulate running both together under different user accounts Id id1; Id id2; System.runAs(fakeUsers[0]) { MyBatch b1 = new MyBatch(); id1 = Database.executeBatch(b1); } System.runAs(fakeUsers[1]) { MyBatch b2 = new MyBatch(); id2 = Database.executeBatch(b2); } Test.stopTest();
Unfortunately it seems that both of the batches still get run with the same user (the actual user running the test rather than either of the fake users). I suspect this is because of the way batches are actually executed during the Test.stopTest method invocation, rather than at some asynchronous time.
Have I come across a bug in the way batches are run in a given user context during testing? Is there a workaround I can use?
bug report"idea".Will update this thread if I find anything useful!
All Answers
You have to call Test.startTest() and Test.stopTest() inside the System.runAs() call and make one unit test method per runAs() desired.
Reason:
Because a batch process executes asynchronously, and calling it within a Test.start/stop means it will force execution of all asynchronous jobs [synchronously] when Test.stopTest() is called. This also means your batch jobs, while technically 'requested' as a different user, are executing as the original user who is running the tests. When you force runAs { Test.start; batch job; Test.stop; } then it is forcing the job to be run while still inside the context of the runAs user.
The downfall of this means you will need one test for each runAs() context you wish to use in regards to batch jobs, because a unit test method only allows one pair of Test.startTest() / Test.stopTest() calls to be utilized.
Please mark this answer as correct if it helped you.
Thanks for taking the time to respond. You have confirmed my concern (as mentioned in my original posting) - the Salesforce infrastructure fails to carry forward the contextual user information from when the execute is triggered in the test. This is, in my opinion, a bug in their implementation. I will see if I can raise this somehow.
Regarding doing two separate Test.startTest()/stopTest() scopes, this would clearly not support the scenario I have described; the test must simulate the "concurrent" rather than "sequential" execution of the two batches. Again, I realize that the way tests handle asynchronous processing isn't truly asynchronous (with the batches actually running during the Test.stopTest() invocation), but I would hope that it would simulate it enough (e.g. perform start on each pending batch, then iterate the executes (as blocks or interleaved) and finally perform the finish for each batch) to support such test scenarios.
Thanks again for your time,
Phil
Here is a summary of the issue as I see it:
When writing an Apex test case, code of the form:
Does not work correctly. The contextual "someUser" for the batch execution gets forgotten, and the user in scope when the Test.stopTest method is called is used instead. I suspect this relates to the way that the test infrastructure postpones asynchronous component execution to run when Test.stopTest is called, where the latter doesn't complete until all async processing has completed.
This seems, to me, to be a "simple" bug, where the delayed execution description does not include the contextual user detail, therefore resulting in the wrong user being used for such executions.
I would like to see this fixed in an up-coming version of Salesforce.
Hey Salesforce support agents, could you have a look at this one and raise a support ticket please? Note that (since I need to simulate two parallel executions of batch processes run by different users) I cannot change the way the scopes are nested:
It needs to work this way to support my testing.
You will need to post this as an Idea at https://success.salesforce.com/ideaSearch for any internal reps to have visibility on it, as they won't be pulling items from a support forum here. Please check there and see if the idea already exists to upvote it, or create a new one otherwise.
Thanks for the info. This actually doesn't align with what I was told by support when they closed the ticket I had raised. Specifically, they said (note the piece in bold that I have highlighted):
We support our standard customers and partners through the developer support boards at https://developer.salesforce.com/. If you have a developer support question, are looking for technical documentation, best practices, code samples and other ways to speed your development time the developer forums are the place for just that. We have dedicated support agents that work the boards to answer questions and review questions to ensure that you get a response."
From my perspective, this is a bug report not an idea suggestion. However, I cannot raise bug reports directly, only on the forums, as per the above quote from the level 1 support team in Salesforce. Pretty silly of them really.
Phil
Premiere Support is different from the Ideas website I sent to you. You will not get a change in the Salesforce Platform backend by creating a question on this forum. The only way you have a chance of that happening is to submit it at the above website, which can be done by anyone and does not require Premiere Support.
Thanks again. I am clear on the difference between Premier Support and the Ideas website. Whilst I understand that Salesforce don't want a flood of "help me!" type support calls, they should ensure that their communications contain accurate information; they clearly gave the wrong impression by what they told me when closing the ticket I had raised.
Please vote for my
bug report"idea".Phil
bug report"idea".Will update this thread if I find anything useful!