1

I am trying to test Schedulable class which is designed to only run once.

Because it's only runs once, I need to test that the System.abortJob is working correctly.

I am using this code to test:

Test.startTest();
Id jobId = FaxScheduledJob.scheduleJob(whatId, whoId, templateName, 1);
Test.stopTest();

Which calls this static helper method to create and schedule the job:

public static Id scheduleJob(Id whatId, Id whoId, String templateName, Decimal numOfAttempts) {

    FaxScheduledJob job = new FaxScheduledJob(whatId, whoId, templateName, numOfAttempts);
    return System.Schedule('Fax Job', schedule(), job);
}

But I get an error when it does the callout to send the fax:

You have uncommitted work pending. Please commit or rollback before calling out

I've looked everywhere and I cannot find any DML that could be causing this.

I suspect that a CronTrigger or AsyncApexJob record is created when I schedule the job, and that is what is causing the error message, but I am not certain.

When I test the Schedulable without actually scheduling it:

SchedulableContext context = new SchedulableContextMock();
Test.startTest();
TwilioFaxScheduledJob job = new TwilioFaxScheduledJob(whatId, whoId, templateName, 1);
job.execute(context);
Test.stopTest();

It does not error.

Here is the full FaxScheduledJob class:

public with sharing class FaxScheduledJob implements Schedulable {

private Id whatId;
private Id whoId;
private String templateName;
private Decimal numOfAttempts;

public FaxScheduledJob(Id whatId, Id whoId, String templateName, Decimal numOfAttempts) {
    this.whatId = whatId;
    this.whoId = whoId;
    this.templateName = templateName;
    this.numOfAttempts = numOfAttempts;
}

public void execute(SchedulableContext context) {

    try {
        // sendFaxAsync is a future method
        FaxService.sendFaxAsync(whatId, templateName, whoId, true, numOfAttempts);
        abortJob(context.getTriggerId());

    } catch (Exception error) {
        System.debug(LoggingLevel.ERROR, error);
    }
}

private static void abortJob(Id jobId) {

    System.runAs(getAdminUser()) {
        if (jobId != null) {
            System.abortJob(jobId);
        }
    }
}

public static Id scheduleJob(Id whatId, Id whoId, String templateName, Decimal numOfAttempts) {

    FaxScheduledJob job = new FaxScheduledJob(whatId, whoId, templateName, numOfAttempts);
    return System.Schedule('Fax Retry Job', schedule(), job);
}

private static String schedule() {

    String hour;
    String min;

    if (Datetime.now().minute() >= 44) {

        hour = String.valueOf(Datetime.now().hour() + 1);
        min = String.valueOf(Datetime.now().minute() - 44); 

    } else {

        hour = String.valueOf(Datetime.now().hour());
        min = String.valueOf(Datetime.now().minute() + 15);  // make this random number between 15 and 30
    }

    String ss = String.valueOf(Datetime.now().second());
    String nextFireTime = ss + ' ' + min + ' ' + hour + ' * * ?';
    return nextFireTime;
}

private static User getAdminUser() {

    User admin = new User();
    admin.Id = 'xxxxxxxxxxxx';
    return admin;
}
}

Question

  1. How can I test this Schedulable and confirm that the job was aborted?
0

1 Answer 1

3

Scheduling the job counts as pending work for the purpose if callouts. If you want to test the callout, manually run execute(null). To test the schedule itself, you'll likely find a @TestVisible flag variable easiest.

public with sharing class MyJob implements Schedulable
{
    @TestVisible static Boolean makeCallout = true;
    public void execute(SchedulableContext context)
    {
        if (!makeCallout) return;

        // make callout
    }
}

@IsTest class MyJobTests
{
    @IsTest static void testCallout()
    {
        // setup

        Test.startTest();
            new MyJob().execute(/*context*/ null);
        Test.stopTest();

        // assertions
    }
    @IsTest static void testSchedulable()
    {
        MyJob.makeCallout = false;

        Test.startTest();
            // schedule the job
            // causing pending work
            // but now there will be no callout
        Test.stopTest();

        // assertions
    }
}

You must log in to answer this question.

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