0

I'm trying to make my tests pass but I can't.

I have My Queueable Class:

public class MyQueueable implements Queueable, Database.AllowsCallouts {
    public MyQueueable() {}

    public static void enqueue() {
        System.enqueueJob(new MyQueueable());
    }

    public void execute(QueueableContext qc) {
      // Some bussiness logic
    }
}

My Schedlable class that enqueue MyQueueable:

global class MySchedlable implements Schedulable {
    global void execute(SchedulableContext scon) {
        MyQueueable.enqueue();
    }
}

And my test class that schedule MySchedlable:

@isTest
public class MyTest {

    @isTest
    private static void myTestMethod() {
       Test.startTest();
       MySchedlable process = new MySchedlable();
       System.schedule('Delete Archived Records', '0 0 7 * * ? *', process);
       Test.stopTest();
       // Here I have some assertions for verify that some records are deleted.
    }

}

I pretend verify that after the Test.stopTest() some records are deleted by MyQueueable. When I run this the test fails, but when I do simply change to this:

@isTest
public class MyTest {

    @isTest
    private static void myTestMethod() {
       Test.startTest();
       MySchedlable process = new MySchedlable();
       process.execute(null);
       Test.stopTest();
       // Here I have some assertions for verify that some records are deleted.
    }

}

The test pass!.

Why?

Thank you!

1
  • 1
    Test.stopTest invokes asynchronous processing synchronously; once Test.stopTest returns, the async processes have completed. However, any async processes set up in that async processing will not themselves be executed, and cannot be. Regardless, you should be writing unit tests; so test your queueable in one unit test and test your schedulable in another. The latter would simply check that the schedulable enqueued the queueable, for example, while the former would check that the queueable did what it is supposed to do.
    – Phil W
    Apr 12, 2023 at 14:28

1 Answer 1

2

As per the documentation:

All asynchronous calls made after the startTest method are collected by the system. When stopTest is executed, all asynchronous processes are run synchronously.

This means that your Schedulable job is collected after Test.startTest. It is then invoked and processed synchronously after Test.stopTest. The Schedulable job processes synchronously to enqueue a Queueable job, but the Queueable job processes asynchronously this time, because we are no longer within Test.startTest and Test.stopTest, so the Queueable job hasn't been collected, only the Schedulable job.

Moreover, you should have separate tests both for your Schedulable and Queueable classes, like this:

Queueable class:

public without sharing class MyQueueable implements Queueable {
    public static void enqueue() {
        System.enqueueJob(new MyQueueable());
    }

    public void execute(QueueableContext qc) {
      Account acc = new Account();
      acc.Name = 'QueueableTest';
      insert acc;
    }
}

Schedulable class:

global without sharing class MySchedulable implements Schedulable {
    global void execute(SchedulableContext scon) {
        MyQueueable.enqueue();
    }
}

Queueable test class:

@isTest
public without sharing class QueueableTest {
    @isTest
    private static void myTestMethod() {
       Test.startTest();
       MyQueueable process = new MyQueueable();
       System.enqueueJob(process);
       Test.stopTest();
       System.assertEquals(1, [SELECT id FROM Account WHERE Name = 'QueueableTest'].size());
    }
}

Schedulable test class:

@isTest
public without sharing class SchedulableTest {
    @isTest
    private static void myTestMethod() {
       Test.startTest();
       String CRON_EXP = '0 0 7 * * ? *';
       MySchedulable process = new MySchedulable();
       String jobID = System.schedule('Create Account Record', CRON_EXP, process);
       Test.stopTest();
       CronTrigger ct = [SELECT Id, CronExpression, TimesTriggered, NextFireTime FROM CronTrigger WHERE id = :jobID];
       System.assertEquals(CRON_EXP, ct.CronExpression);
    }
}
3
  • the unit test for the schedulable should not assert CronTrigger as that adds no info since SFDC s guaranteed to schedule the job - instead - it should query AsyncApexJob to see if a queueable was created as that is what the OPs schedulable is supposed to do
    – cropredy
    Apr 12, 2023 at 17:30
  • Somewhat disagree. Testing the Schedulable itself is always smoke testing OOTB functionality.
    – Adrian Larson
    Apr 12, 2023 at 17:47
  • @AdrianLarson I understand your point. Perhaps asserts in the test class are redundant, but the test method itself adds code coverage to the org.
    – DevelBase2
    Apr 12, 2023 at 18:59

You must log in to answer this question.

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