0

I have a test class with the following function in it:

@isTest
private static void testDequeue() {
    ... // a LOT of setup code here

    Test.startTest();
    Savepoint sp = Database.setSavepoint();
    String query = ...; // some query

    // CODE PART A
    JobA job = new JobA(query, false);
    Database.executeBatch(job, 10);
    List<ObjectA> records = [ ... ];
    System.assert(records.size() > 0);
    ... // a LOT more assertions
    Database.rollback(sp);

    // CODE PART B
    JobB job = new JobB(query);
    Database.executeBatch(job, 10);
    List<ObjectA> records = [ ... ];
    System.assert(records.size() > 0);
    ... // the same assertions as before
    Test.stopTest();
}

I'm testing two Jobs, JobA and JobB which both do the same thing. Both require the same setup code, which is why it is easier for me to test them in the same function. So, I'm using savepoints to make JobA do something, do some tests, then undo what JobA did, make JobB do the same thing, and then run the same tests.

The issue is, this code throws an AssertionError for the first assert statement:

System.AssertException: Assertion Failed

I've confirmed the Savepoint code is the reason, because when I remove it (as well as the PART B code), the error goes.

What's even more annoying is that, I've a lot of scenarios like this, and this code works for some, and fails for others. I'm not able to figure out why that happens. Is it a bug? Or is there something about savepoints I should know?

5
  • The async code between the start and stop test runs when stoptest is hit. I do not believe that the order of execution is guaranteed. You would be best served to use the Test setup annotation and break them out into two separate methods
    – Eric
    Mar 15, 2017 at 22:42
  • I guarantee this error is not "unprecedented". Someone else has hit it before. That said, you don't even include the error message...Always include error messages verbatim.
    – Adrian Larson
    Mar 15, 2017 at 22:52
  • @AdrianLarson Well, I've added it, don't know how much it'd help though. Also, unprecedented for me. :P
    – coldspeed
    Mar 16, 2017 at 5:32
  • @Eric I've removed the start and stop functions but the issue still persists.
    – coldspeed
    Mar 16, 2017 at 5:41
  • That's because no the batches will not actually run
    – Eric
    Mar 16, 2017 at 11:13

1 Answer 1

1

This wont work for a few reasons

  1. Without putting your batch invocations in separate startTest/stopTest blocks, you have no guarantee they will finish one after the other (they are two independent asynchronous transactions)
  2. Savepoint works per transaction and you can't rollback changes across transaction. In other words, each batch execute invocation can only role its own transaction back. There is an excellent post on this here: Rollback whole Batch

You should just make an @setup method and break your 2 tests into 2 methods with 2 startTest/stopTest blocks.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .