just right now, while deploying some code from Sandbox environment to the Production one, I was noticing something strange within a test class that should have the aim to test a Batch class. I notice that the executeBatch() call is not enclosed within Test.startTest()and Test.stopTest() methods.

Now, as per documentation ( https://developer.salesforce.com/docs/atlas.en-us.apex_workbook.meta/apex_workbook/apex_batch_2.htm), these methods should be used so that the asynchronous call (like my executeBatch()) are collected and executed synchronously after the Test.stopTest() call.

However, without using these two methods, my test runs correctly.

  • Now I wonder: is using start/stopTest() an "optional" best practice?

  • There's something other I'm missing?

2 Answers 2

  • You are lucky that the asynchronous call executes even before you start the assertions (or I am not sure whether you are having any assertions post the asynchronous call)

  • Since you are running within 100 SOQL limit in your whole context, there is no change in your test (with or without starttest())

Key Advantages:

  • You will get complete assurance that all asynchronous jobs are completed, (similar to Thread.join in java
  • You will get extra 100 SOQL quota in Test context

The startTest method does not refresh the context of the test: it adds a context to your test. For example, if your class makes 98 SOQL queries before it calls startTest, and the first significant statement after startTest is a DML statement, the program can now make an additional 100 queries. Once stopTest is called, however, the program goes back into the original context, and can only make 2 additional SOQL queries before reaching the limit of 100.

  • Thank you, it's a very clear answer. A last doubt.. without startTest(), anyway the test context waits for all asynchronous executions to be completed before giving the result? (for results I mean code coverage or, generally, test result)
    – user9959
    Mar 4, 2016 at 12:17

Yes you are right. It is optional to enclose your batch class execution inside startTest and stopTest. But as test class are for validating your code, so you should write some assert after your batch execution(Otherwise it will become code covering test and not unit test :) ), and in that case your assert will fail, as batch will not finish (asynchronous execution).

Ex. You have a batch class which inserts 100 records, then

Integer totalCountBeforeBatch = //get the count
//execute your batch
Integer totalCountAfterBatch = //get the count
system.assertEquals( totalCountBeforeBatch + 100 , totalCountAfterBatch  );

will validate your functionality is correct or not.

And if you remove start and stop test then you would have to remove the assert statement at last otherwise it will always fail.

And not only batch classes, for future methods also you should call inside start and stop test. At line Test.stopTest(), it will make sure that all asynchronous call are finished before executing the next line.

P.S : I 100% agree with @Karthikselva's answer. Just thought of adding an example.

  • Thank you Saumya! About your statement "and in that case your assert will fail, as batch will not finish (asynchronous execution)" I would wonder: without using start/stop, is it sure the assertion will be evalueated before the end of execution of asynchronous actions or is it "causal" (i.e., depending on when the asymnchrounous call are queued)? Surely it can happens, but does it always ? @karthikselva says "you are lucky that the asynchronous call executes even before you start the assertions", so I think it's casual ..this is only a philosophical question anyway
    – user9959
    Mar 4, 2016 at 15:08

You must log in to answer this question.