0

I have below batch class which just updates the account name, which is working fine:

global class BatchClass3 implements Database.Batchable<sObject>
{
    global Database.QueryLocator start(Database.BatchableContext bc)
    {
        String query = 'Select Name from Account';
        return Database.getQueryLocator(query);
    }
    global void execute(Database.BatchableContext bc, List<Account> records)
    {
        List<Account> accounts = new List<Account>();
        for(Account acc : records)
        {
            acc.Name=acc.Name+' Updated by Batch';
            accounts.add(acc);
        }
        update accounts;
    }
    global void finish(Database.BatchableContext bc)
    {
    }
}

When I wrote the below test class and executed it, it is giving the below error:

System.AssertException: Assertion Failed: Expected: Account 1 Updated by Batch, Actual: Account 1.

This means that the Accounts are not getting updated. Can you please let me know where I am going wrong.

@isTest
private class BatchTest
{
    static testMethod void testBatch()
    {
        List<Account> accs = new List<Account>();
        for(Integer i=1;i<=6;i++)
        {
            Account a = new Account();
            a.Name='Account '+i;
            accs.add(a);
        }
        insert accs;
        Test.startTest();
            Database.executeBatch(new BatchClass3());
            System.assertEquals(6, [Select count() from Account]);
            //System.assertEquals('Account 1 Updated by Batch',[Select Name from Account limit 1][0].Name);
            Integer i=1;
            for(Account a : [Select Name from Account] )
            {
                System.assertEquals('Account '+i+' Updated by Batch', a.Name);
                i++;
            }
        Test.stopTest();
    }
}
  • 1
    You add the assertion after the Test.stoptest() line to be sure the batch has finished. – Martin Lezer Jun 3 at 12:53
  • You need to make sure you query the ID of the accounts. – Phil W Jun 3 at 12:54
0

Asynchronous apex is executed after executing the Test.stopTest() line i.e. All asynchronous calls made after the startTest method are collected by the system. When stopTest is executed, all asynchronous processes are run synchronously.

Hence, if you have your assert statements before Test.stopTest(), it won't pass because at that point of time, your batch wouldn't have been executed.

So whenever testing an asynchronous apex (its always a best practice whether asynchronous or synchronous), you should always have the assert statements after Test.stopTest() method.

You can find the significance of Test.startTest() and Test.stopTest() at this link.

Regarding the assert statements

System.assertEquals(6, [Select count() from Account]);

This above assert statement seems to be correct, but the other one

for(Account a : [Select Name from Account] )
{
    System.assertEquals('Account '+i+' Updated by Batch', a.Name);
    i++;
}

I am not sure, this will always work because of following reasons

  • Your batch only appends an integer, i.e. the value would be Account 1 whereas you are asserting it with Account 1 Updated by Batch, which will fail, unless you are appending the value Updated by Batch from either Trigger/Workflow/Process Builder/Flow.
  • When you are comparing the values fetched from the database, it is not always necessary that it will return the records in the same order in which it were inserted, i.e. if Account 2 is retrieved first and if you are comparing it with Account 1 Updated by Batch, then again it will fail.
1

Batch, Future, Queuable, Scheduler are called Asynchronous apex. They run when the current transaction finishes and committed. There is no SLA for Async apex , ie they can run anytime, can be in few minutes or an hour.

While testing Async Apex, you have to demand that Async Apex should run asap in same transaction so that you can assert it.

This can be done by putting the invocation in between Test.startTest(); and Test.stopTest();

Thus in your case. The asserting will be after the stop test.

@isTest
private class BatchTest
{
    static testMethod void testBatch()
    {
        List<Account> accs = new List<Account>();
        for(Integer i=1;i<=6;i++)
        {
            Account a = new Account();
            a.Name='Account '+i;
            accs.add(a);
        }
        insert accs;
        Test.startTest();
        Database.executeBatch(new BatchClass3());

        Test.stopTest();

        System.assertEquals(6, [Select count() from Account]);
        //System.assertEquals('Account 1 Updated by Batch',[Select Name from Account limit 1][0].Name);
        Integer i=1;
        for(Account a : [Select Name from Account] )
        {
            System.assertEquals('Account '+i+' Updated by Batch', a.Name);
            i++;
        }
    }
}

Src: How do I test asynchronous Apex?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.