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 – Santanu Boral Feb 15 '17 at 17:47
  • 3
    Hard-coded Ids...big no-no! – Adrian Larson Feb 15 '17 at 17:47
  • As @SantanuBoral said, we'd love to see your progress on the Test Class so far. – Sebastian Kessel Feb 15 '17 at 18:11
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? – DoubleA9281 Feb 15 '17 at 21:01
  • Simply use, SELECT Id From BusinessHours WHERE Name ='<your business hour name>' – Santanu Boral Feb 15 '17 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 – DoubleA9281 Feb 15 '17 at 21:56
  • Thank you for your answer I was able to get my code to work now. – DoubleA9281 Feb 15 '17 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. – DoubleA9281 Feb 15 '17 at 20:48

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.