I have written a scheduled apex class and apex job that I want confirm if it works. How can I test/verify it will work as expected without waiting for it to run at its scheduled time for one record and also a number of records?
1 Answer
Creating a unit test class (e.g. @isTest private class MyTest{ /* test things */}
) is how you write automated tests (that can/must be run when you deploy new code (or changes to existing code) to a production environment).
As a general rule, you should only test the things that you have control over (and visibility of).
You don't have control over how Salesforce causes Future/Scheduled/Queueable/Batch/Continuations (collectively, our asynchronous execution options) to run, so you shouldn't test that behavior (and instead trust that Salesforce knows and tests how their features work).
What you do have control over, however, is what happens when your code is run asynchronously.
If your method is public
, then there's nothing stopping you from calling it directly (and synchronously).
Given the following example class
public class MySchedulable implements Schedulable{
public static void execute(SchedulableContext ctx){
// do work
}
}
A corresponding test class would look something like this
@isTest
private class MySchedulableTest{
@testSetup
static void doSetup(){
// Create and insert any SObject records, Custom Setting records, etc...
// that you need for your code to be able to run
}
@isTest
static void execute_TestNormalRun(){
// Do any test-specific setup here
// call the code you wish to test directly (if possible)
Test.startTest();
// The SchedulableContext doesn't have too much use.
// It's typical to completely ignore it in the actual method, so we
// can usually just pass 'null' into the method.
// This is calling the method directly, which means that it will be executed
// synchronously (except for @future annotated methods)
MySchedulable.execute(null);
Test.stopTest();
// Gather results (which probably means you need to perform a query to
// see which SObjects were inserted/updated/deleted) and make assertions
// to verify that the results of running your code are what you expected
}
}
Here, the Test.startTest()
and Test.stopTest()
aren't usually that important.
When you're writing tests for code that causes asynchronous code to be executed though, they're vital. They cause one level of async execution to be gathered, and then executed synchronously. If your async code isn't run synchronously, they will not be run before the test is over.
Let's say you have the following class
public class MyFutureMethodClass{
@future
public static void myFutureMethod(){
system.debug('@future method run');
}
}
and you have a client class (i.e. code that uses another class or piece of functionality)
public class FutureClient{
public void doWork(){
MyFutureMethodClass.myFutureMethod();
}
}
You would write test methods for FutureClient
like so
@isTest
private class MyFutureClientTest{
@testSetup
static void doSetup(){
// Create and insert SObject records that MyFutureClient requires to run.
}
@isTest
static void doWork_EnsureAsyncCodeRuns(){
// any test-specific setup here
Test.startTest();
MyFutureClient client = new MyFutureClient();
// Execute the code that causes async work to be requested
client.doWork();
// Test.stopTest() causes async work to be run immediately afterwords, which
// makes it run synchronously (for this test only)
Test.stopTest();
// At this point, the normally async code has been run, and you can
// run queries (and the like) to gather the results of that code being run
}
}
-
Thank you. I am not trying to write a unit test. I would to just execute the code for a someone that does testing. So they can verify it works as expected. Is there way to do that without a unit test?– user58Commented Mar 22, 2022 at 9:45
-
1@user58 The same idea applies outside of unit tests. You call the method directly (via anonymous apex).– Derek FCommented Mar 22, 2022 at 12:29
-
Test.startTest()
andTest.stopTest()
?