7

So I have a trigger and a schedule class. The trigger will fire upon update on an object and schedule a job which will execute the scheduled class. There is some logic in the trigger related to non-working hours, weekends and holidays. It will usually schedule the job 1 hour after insert (due to business requirement). but if insert happens over the weekend, afterhours, or holidays. It will schedule the next business day 8am.

My problem is my test class does not cover everything. I insert the object in test class, and depends on what time I run the test, it will cover different part. Like if I run during business hours, the weekend, holiday logic doesn't get covered, etc.

My question is there anyway in test class we can set the Datetime.Now to any date and time we want? thanks very much

2
  • I think scheduled classes may start right away when they're run as part of a test. I'll see if I can chase down a reference for that.
    – Jagular
    Dec 30, 2014 at 23:19
  • Do you really want to test the clock ticking ?
    – Martin
    Dec 31, 2014 at 8:36

3 Answers 3

10

A solution to this is as follows:

//  -----------------------------------------------
//  now     : getter/setter to have testemthod-driven different values for now; see also today
//  -----------------------------------------------
public static DateTime now      {get {return now == null ? DateTime.now() : now;} set;}

//  -----------------------------------------------
//  today : getter/setter to have testemthod-driven different values for today; see also now
//  -----------------------------------------------
public static Date today {get {return today == null ? Date.today() : today;} set;}

Then your trigger needs to always get the current time by using Util.now. In PROD, it will always return the true "now" time.

But your testmethods can call Util.now = testTime; before doing DML on the triggered SObject. Your trigger code will then get a fake datetime so you can verify that your CronTrigger is properly setup.

3
  • thanks - I used the solution when testing automatic renewal batch jobs that needed leap year use cases
    – cropredy
    Dec 31, 2014 at 18:49
  • the methods should be public static, just an FYI Jan 4, 2017 at 21:29
  • @Programatic - no kidding; I revised the implementation as well to use properties as per abd3721 since that is a cleaner implementation
    – cropredy
    Jan 4, 2017 at 21:35
3

Inspired by Crop1645's answer, here's an answer in the form of a single property accessor:

/**
 * Allows the current Date and Time to be set/spoofed
 * this is generally only useful for test classes
 */
public static DateTime now {
  get {
    return (now == null) ? DateTime.now() : now;
  }
  set;
}

This allows you to run:

system.assertEquals(DateTime.now(), now);
now = DateTime.now().addYears(-1);
system.assertNotEquals(DateTime.now(), now);
2

Idea for enhancement of previous solutions, to prevent incorrect usage of now and today in production environment and enable changes only for unit tests:

public class ForceUtils {

@TestVisible
private static Datetime now;

@TestVisible
private static Date today;

public static Datetime now() {
    return now == null ? Datetime.now() : now;
}

public static Date today() {
    return today == null ? Date.today() : today;
}}

You must log in to answer this question.

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