Testing BatchApexErrorEvent trigger

I have a batch class which implements the Database.RaisesPlatformEvents interface. This interface has recently been introduced and helps log unexpected exceptions: https://developer.salesforce.com/docs/atlas.en-us.218.0.object_reference.meta/object_reference/sforce_api_objects_batchapexerrorevent.htm

It works well and I have implemented a trigger which calls a handler class to log the error permanently in a separate object:

trigger LogBatchApexErrorEvent on BatchApexErrorEvent (after insert){
    if(Trigger.IsInsert && Trigger.IsAfter){
        LogBatchApexErrorEvent_Handler.persistLog(Trigger.New);
    }
}

My test batch class looks somewhat like this:

public with sharing class TestBatch implements Database.Batchable<sObject>, Database.RaisesPlatformEvents {
    public Database.QueryLocator start(Database.BatchableContext BC){
        String query = 'SELECT Id FROM Account';
        return Database.getQueryLocator(query);
    }

    public void execute(Database.BatchableContext BC, List<SObject> scope){
        Integer i = 1 / 0;
    }

    public void finish(Database.BatchableContext BC){ }
}

The problem is, it seems impossible to write a test class for this. I currently have this test method:

static testMethod void testBatchApexErrorEvent() {
    insert new Account(Name = 'Test Account');

    try {
        Test.startTest();
            TestBatch tb = new TestBatch();
            Database.executeBatch(tb); 
        Test.stopTest();
    } catch(System.MathException e){}

    System.assertEquals(1, [SELECT Id FROM Log__c].size());
}

However, the BatchApexErrorEvent is a Platform Event so is asynchronous – which means that at the time my System.assertEquals line runs it hasn’t actually fired yet.

I also tried throwing a BatchApexErrorEvent manually, but I get the following error: DML operation Insert not allowed on BatchApexErrorEvent. This is my attempt:

BatchApexErrorEvent event = new BatchApexErrorEvent();
EventBus.publish(event);

Despite this being the way BatchApexErrorEvents are tested in this blogpost on the topic, it doesn’t seem possible anymore: https://developer.salesforce.com/blogs/2019/01/building-a-batch-retry-framework-with-batchapexerrorevent.html

Considering there is no way to either a) test two asynchronous processes in one test method or b) manually throw a BatchApexErrorEvent, is there currently any way for me to test this? 🙂

Answer

So as I can see from your code Divide by zero will throw an exception. Which inturn will fire BatchApexErrorEvent . The thing we need to look for is this is the test context. The events will not deliver unless you force it to deliver.

Thus you have to call Test.getEventBus().deliver();, this will ensure your triggers on platform events are fired and you can do successful assert.

static testMethod void testBatchApexErrorEvent() {
   insert new Account(Name = 'Test Account');

   try{
        Test.startTest();
        TestBatch tb = new TestBatch();
        Database.executeBatch(tb); 
        Test.getEventBus().deliver();
        Test.stopTest();
    } catch(System.MathException e){}
    Test.getEventBus().deliver(); 

    System.assertEquals(1, [SELECT Id FROM Log__c].size());
}

Source: Deliver Test Event Messages on Demand with Test.getEventBus().deliver()

Attribution
Source : Link , Question Author : Koen Wesselman , Answer Author : Koen Wesselman

Leave a Comment