0

I am work on test class for the following code. The code uses the business hours from Salesforce and applies a task to anything lead that comes in after business hours. The issue is I cant get the test class to simulate after hours.

I have tried to just set the isWithin var to false I have tried to add time to the target time. I am running out of ideas.

trigger Working_Lead_business on Lead (after insert) {
    public datetime mydate = system.now();
    List<Task> tsk_lst = new list<task>{};
    BusinessHours bh = [select id from businesshours where id = '01m50000000LjJ5'];
    Boolean isWithin = BusinessHours.isWithin(bh.id, mydate);


    For(Lead l: Trigger.new) {
        if(l.Status == 'New' && isWithin == false){
            Task taskcreate = new Task();
            taskcreate.OwnerId = '00550000005ThR4';
            taskcreate.WhoId = l.id;
            taskcreate.Subject = 'email';
            taskcreate.Priority = 'Normal';
            taskcreate.Type = 'After Hours';
            taskcreate.Status = 'Completed';
            tsk_lst.add(taskcreate);
        }  
    }
    if (tsk_lst == null){
        /*Do nothing*/
    } else {
        upsert tsk_lst;
    }
}
3
  • Can you post your code of test class whatever you have tried Commented Feb 15, 2017 at 17:47
  • 3
    Hard-coded Ids...big no-no!
    – Adrian Larson
    Commented Feb 15, 2017 at 17:47
  • As @SantanuBoral said, we'd love to see your progress on the Test Class so far. Commented Feb 15, 2017 at 18:11

2 Answers 2

0

Create a separate BusinessHourService to maintain business hours related methods and access business hour method from any of your classes or triggers.

Do not hardcode any ids.

public with sharing class BusinessHoursServices
{
    //retrieves & assign the Organization level Business Hours to defaultBH 
    static BusinessHours defaultBH
    {
        get
        {
            if (defaultBH == null)
                defaultBH = [SELECT Id FROM BusinessHours WHERE IsDefault = true];
            return defaultBH;
        }
        private set;
    }

    public static Boolean isWithin()
    {
        return isWithin(Datetime.now());
    }
    public static Boolean isWithin(Datetime input)
    {
        return BusinessHours.isWithin(defaultBH.Id, input);
    }

    public static  Datetime nextStartDate()
    {
        return nextStartDate(Datetime.now());
    }
    public static Datetime nextStartDate(Datetime input)
    {
        return BusinessHours.nextStartDate(defaultBH.Id, input);
    }

}

Change your trigger like this to create a mock date for testing with Test.isRunningTest()

public datetime mydate;
if(!Test.isRunningTest())
{
    mydate = System.now();
}
else
{
    mydate = Datetime.newInstance(2017, 2, 18); //saturday
}
List<Task> tsk_lst = new list<task>{};
BusinessHours bh = BusinessHoursServices.defaultBH;
Boolean isWithin = BusinessHoursServices.isWithin(mydate);

Now it will definitely satisfy isWithin == false condition.

Ideally create separate trigger handler class to put all the logic in that class.

Make mydate as @testVisible so that you will assign any values from your test class.

Or, create a boolean variable isBusinessHourTesting in your class and make it true in the test class. And finally use this logic:

if((Test.isRunningTest() && isBusinessHourTesting))
{
    mydate = Datetime.newInstance(2017, 2, 18); //saturday
}
else
{
   mydate = System.now();
}
4
  • Thank you for your response. I am not using the default business hours I had to create a separate set for my csr group. How would you go about getting the id without hard-coding? Commented Feb 15, 2017 at 21:01
  • Simply use, SELECT Id From BusinessHours WHERE Name ='<your business hour name>' Commented Feb 15, 2017 at 21:26
  • At fist thought I wasn't sure what the difference would be between the name or just hardcore the ID. But, I get it now. The name can be deleted and added back in without effecting the code. Thank you Commented Feb 15, 2017 at 21:56
  • Thank you for your answer I was able to get my code to work now. Commented Feb 15, 2017 at 21:57
1

A couple notes on your code:

  • Never hard-code Id values under any circumstances.
  • Your tsk_list variable cannot be null, so don't check that condition.

This code is a classic example of why Separation Of Concerns and a Service layer in your code are advantageous. If you split out this service method, it is quite easy to test:

public with sharing class LeadService
{
    public static void createAfterHoursTasks(List<Lead> records)
    {
        // task creation logic
    }
}

You may also wish to split out a filter method to get just the records with a matching status:

public static List<Lead> filterStatus(String status, List<Lead> records)
{
    List<Lead> filtered = new List<Lead>();
    for (Lead record : records)
        if (record.Status == status)
            filtered.add(record);
    return filtered;
}

You should also look into handler patterns, but regardless your trigger code can now be simplified to:

if (!BusinessHours.isWithin(bh.Id, Datetime.now())
{
    List<Lead> newLeads = LeadService.filterStatus('New', trigger.new);
    LeadService.createAfterHoursTasks(newLeads);
}

You could even make your isWithin flag @TestVisible so you can easily control it during test execution.

1
  • Thank you for your response I need to look in detail into a lot of the items you spoke of. Commented Feb 15, 2017 at 20:48

You must log in to answer this question.

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