Testing Quartz CronTrigger trigger
-
21-08-2019 - |
Question
Assuming that I have a CronTriggerBean
similar to
<bean id="midMonthCronTrigger" class="org.springframework.scheduling.quartz.CronTriggerBean">
<property name="jobDetail" ref="reminderJobDetail" />
<property name="cronExpression" value="0 0 6 15W * ?" />
</bean>
What is the best way to test that this bean will actually trigger at its specified date, i.e. on the weekday closest to the 15th of each month at 6 AM?
Update: This is supposed to be an unit test, so I'm not going to fire up a VM or change the system time.
Solution
Well firstly, there's no point in testing CronTriggerBean
itself. It's part of the spring framework, and has already been tested.
A better test might be to test that your cron expression is what you expect. One option here is to use Quartz's CronExpression
class. Given a CronExpression
object, you can call getNextValidTimeAfter(Date)
, which returns the next time after the given Date when the expression will fire.
OTHER TIPS
I used CronMaker only to be sure if my cron expression is well formed, check it out: http://www.cronmaker.com/
- You can always wait until the 15h of July.
- Being more serious... If it's really a key part of the application and I you need to have it tested fully. I would recommend using some virtualization setups and have the application installed within some guest machine. Then you could play with the system clock and test different date/times without spending a whole month on it. Moreover there's nothing that should stop you from automating such tests.
For those who don't use the Quartz scheduler, but instead use the TaskSchedular
directly:
CronSequenceGenerator generator = new CronSequenceGenerator("0 0 8 */1 * *");
Date next = generator.next(prev);
You also can get the trigger bean from spring and invoke the getFireTimeAfter
method to finish.
I found a cool documentation here about testing the CronExpression
:
http://www.nurkiewicz.com/2012/10/testing-quartz-cron-expressions.html
The C# implementation will be something like this:
void Run()
{
//var collection = findTriggerTimesRecursive(new CronExpression("0 0 17 L-3W 6-9 ? *"), DateTime.UtcNow);
var collection = findTriggerTimesRecursive(new CronExpression("0 0/15 * 1/1 * ? *"), DateTime.UtcNow);
Console.WriteLine(DateTime.UtcNow);
foreach (var item in collection)
{
Console.WriteLine(item);
}
}
public List<DateTimeOffset> findTriggerTimesRecursive(CronExpression expr, DateTimeOffset from, int max = 10)
{
var times = new List<DateTimeOffset>();
var next = expr.GetNextValidTimeAfter(from);
while (next != null && times.Count < max)
{
times.Add(next.Value);
from = next.Value;
next = expr.GetNextValidTimeAfter(from);
}
return times;
}
This is a cool demo. But at the end, I end using Simple Schedule.
var trigger = TriggerBuilder.Create()
.WithIdentity("trigger3", "group1")
.WithSimpleSchedule(
x =>
{
x.WithIntervalInMinutes(15);
x.RepeatForever();
}
)
.ForJob("myJob", "group1")
.Build();
Because this is executed immediately and then every x time.