0

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?
2

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
    }
}

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.