Salesforce Asked on November 13, 2021
I am trying to write a test for my trigger that will queue up some job, unfortunately according to Salesforce, tests can’t have chain-able queues.
https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_queueing_jobs.htm
You can’t chain queueable jobs in an Apex test. Doing so results in an
error. To avoid getting an error, you can check if Apex is running in
test context by calling Test.isRunningTest() before chaining jobs.
So when I run my test I get this error:
System.AsyncException: Maximum stack depth has been reached.
I need to find some way to get around this.
One way I was thinking is to let the trigger know that it’s a test, so that it won’t queue up the job. Here is my current code:
My Trigger class:
trigger MyTrigger on MyObj(after insert) {
String CRON_EXP = '0 0 0 ? * * *';
MyObjScheduler schedule = new MyObjScheduler ();
String jobId = System.schedule('MyTrigger', CRON_EXP, schedule);
}
My Scheduler Class:
global class MyObjScheduler implements Schedulable {
global void execute(SchedulableContext ctx) {
// Other business logic
MyObjQueueableJob curJob = new MyObjQueueableJob ();
System.enqueueJob(curJob);
}
}
My Queueable
public class MyObjQueueableJob implements Queueable {
public void execute(QueueableContext context) {
// Other business logic
System.enqueueJob(otherJobs);
} }
If there is a way to communicate with Trigger, then I can just write it like this:
trigger MyTrigger on MyObj(after insert) {
String CRON_EXP = '0 0 0 ? * * *';
Boolean IsTest = false; // How to change this to true?
MyObjScheduler schedule = new MyObjScheduler ();
if (!IsTest) {
String jobId = System.schedule('MyTrigger', CRON_EXP, schedule);
}
}
Is this possible?
Using if(!Test.isRunningTest())
allows you to purposefully execute (or not execute) code if you're running in a test context.
That can help you out of some simple situations, but a consequence of not running particular bits of code is that the code that does not get run during a test also does not get code coverage from that test.
You're going to need to cause your code to run at some point, and chained queueable jobs are likely still going to present an issue.
One potential answer to that is to stick to only writing unit tests (as opposed to, say, integration tests). The test only stresses one class, and any method from any other class that gets called needs to be stubbed/mocked.
This approach requires extra setup if you're using the Apex Mocks framework or The Stub API.
It may also mean that you need to design and architect your code in such a way that you can perform dependency injection.
Another option is to use Test.isRunningTest()
to determine when you should enqueue your queueable job, and when you should just call the execute()
method like it were any other method.
It may not be obvious at first, but there really is nothing stopping you from doing the following:
MyObjQueueableJob asyncWork = new MyObjQueueableJob();
asyncWork.execute(null);
The QueueableContext
parameter can just have null passed with it. QueueableContext
is an interface that provides one method, getJobId()
, and that information doesn't really have much in the way of uses.
The advantage of this option is that you still run your queueable code in your test, and you can work around the chaining restriction.
The drawback of this approach is that everything you're running (in the test) is no longer async, and you won't get a fresh set of limits like you would outside of a test context. Running into governor limits may be a very real concern here.
Using Test.isRunningTest()
to alter the path of execution in test contexts likely means that you won't be able to attain 100% coverage.
If you ask me though, 100% coverage is a nice thing to strive for but not really all that important. It's far more important that you write many test methods to cover a wide range of possible code paths (which naturally leads to high coverage) and make a ton of assertions (to validate that running your code ends up doing what you think it should be doing).
Answered by Derek F on November 13, 2021
If I understood your question correctly, in your trigger, you can write something like this:
String jobId;
if(!Test.isRunningTest()){
jobId = System.schedule('MyTrigger', CRON_EXP, schedule);
}
Answered by Shailesh Patil on November 13, 2021
Get help from others!
Recent Questions
Recent Answers
© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP