Is there any way of confirming that an @future method has been called/queued in a test class?

I have a Controller (FooController) which calls an @future method (bar()) belonging to another class (FooServices).

Ideally in my test class for this Controller (FooControllerTest) I only want to test that the @future method has been called, I don’t want to test its effects as that’s FooServicesTest‘s job.

I know that I can use Test.startTest() and Test.stopTest() to see the effects of an @future method in a test class, but is there any way of identifying that a @future method has been called/queued up in a test class?

Since code is generally easier to understand than words, here is an example of what I would like to be able to do:

FooController

public class FooController
{
    public PageReference save()
    {
        // Do some operations...

        // Call my @future method
        FooServices.bar();

        return null;
    }
}

FooServices

public class FooServices
{
    @future
    public static void bar()
    {
        // Do some things in the future...
    }
}

FooControllerTest

@isTest
private class FooControllerTest
{
    @isTest
    private static void save_ValidData_CalloutQueued()
    {
        // Setup my test data...
        FooController controller = new FooController();
        controller.save();
        // Is this part possible? THE BELOW METHOD NAME IS ENTIRELY FICTIONAL
        System.assert(System.isFutureJobQueued('FooServices.bar'));
    }
    // OR...
    @isTest
    private static void save_ValidData_CalloutExecuted()
    {
        FooController controller = new FooController();
        Test.startTest();
        controller.save();
        Test.stopTest();
        // Yet another fictional method...
        System.assert(System.hasFutureJobExecuted('FooServices.bar'));
    }
}

Answer

Yes!

I love this question, as it’s one of my pet peeves. People don’t test @future calling methods because they don’t know it’s possible.

Enter the magic of two key methods:

Test.StartTest();
Test.StopTest();

When you utilize these methods — and you should! they do a couple of key things for you.

  1. they reset your governor limits so you can test if your actual code is going to hit Limits.
  2. Test.StopTest(), actually forces your @future methods to run right now and return before progressing to the next step.

so, in your test example, if you take your exact test and add those two methods thusly:

@isTest
private class FooControllerTest
{
    @isTest
    private static void save_ValidData_CalloutQueued()
    {
        // Setup my test data...
        FooController controller = new FooController();
        Test.StartTest();
        controller.save();
        Test.StopTest();
        // You can actually now assert that yes, it indeed was queued, 
        // and has run, and has returned data. Since this is a callout? 
        // look at the callout mocks for more info on returning mock 
        // data to assert on.
        System.assert(System.isFutureJobQueued('FooServices.bar'));
    }

}

With Regards to just identifying of a job has been queued:

Select ApexClassId, CompletedDate, CreatedById, CreatedDate, ExtendedStatus, Id,
JobItemsProcessed, JobType, LastProcessed, LastProcessedOffset, MethodName, 
NumberOfErrors, ParentJobId, Status, TotalJobItems from AsyncApexJob

This object, (and query above) should list all pending async apex jobs including enqueued @future methods. I expect (but have never tried) that you could build a where clause based on MethodName. ApexClassId would likely work as well, but would be ugly as the Id’s may be hard to come by dynamically.

Attribution
Source : Link , Question Author : Alex Tennant , Answer Author : Kevin P

Leave a Comment