How to test that Apex Batch finish() sends an email?

I have a Batch class that sends an Email from its finish method and want to test that. a But….I cannot test it. The the above test fails as there was no email invocation at all. BUT: I see it in the Limits view of my Dev Console that indeed one email invocation happens. Why?!

The batch class:

public MyBatch implements Database.Batchable<SObject> {


    public void finish(Database.BatchableContext context) {

The test method:

private static void sendsEmailOnFinish() { 
    MyBatch b = new MyBatch();

    // Verify
    System.assertEquals(1, Limits.getEmailInvocations());

I thought this might be connected to using Test.startTest() and stopTest() but even moving the assertEquals before the Test.stopTest() doesn’t make my test run.


Batches don’t run until stopTest(), and stopTest() restores the test method’s limits after the batch executes before it returns. This means that your test method will never see that limit set unless it sends an email itself (which, of course, will never be delivered/sent).

You have two ways to handle this:

  1. Don’t bother with the assert. Assuming the email isn’t sent, an exception is thrown; if you don’t catch the exception in finish, the exception will be thrown out to the test method, and if you don’t have a try-catch block, the entire test automatically fails anyways, which is the point of your assert call, right?

  2. Set a static @TestVisible method in your MyBatch class. On the last line of finish, set that value to Limits.getEmailInvocations(). Once you come back from the batch, you can examine this value.

global class MyBatch ... {
    @TestVisible static Integer emailLimits;
    global void finish(...) {
        MyBatch.emailLimits = Limits.getEmailInvocations();

Source : Link , Question Author : Robert Sösemann , Answer Author : sfdcfox

Leave a Comment