0

I am stuck on a test method and any help would be highly appreciated.

To provide some context: I created a method that queries a specific BusinessHours record on the DB and validates if a Case was created within Business Hours (using isWithin method).

As I cannot specifically create the BusinessHours record during the test setup neither assure that it will exist on every scratch org decided to use fflib's ApexMocks in order to mock the Selector method (as suggested here).

The mocking itself is working, and this is the code I am using to generate a test BusinessHours record:

BusinessHours testBusinessHours = new BusinessHours(
    Id = fflib_IDGenerator.generate(Schema.BusinessHours.SObjectType), 
    Name = 'Test Business Hours',
    MondayStartTime = Time.newInstance(9, 0, 0, 0),
    MondayEndTime = Time.newInstance(23, 0, 0, 0),
    TuesdayStartTime = Time.newInstance(9, 0, 0, 0),
    TuesdayEndTime = Time.newInstance(23, 0, 0, 0),
    WednesdayStartTime = Time.newInstance(9, 0, 0, 0),
    WednesdayEndTime = Time.newInstance(23, 0, 0, 0),
    ThursdayStartTime = Time.newInstance(9, 0, 0, 0),
    ThursdayEndTime = Time.newInstance(23, 0, 0, 0),
    FridayStartTime = Time.newInstance(9, 0, 0, 0),
    FridayEndTime = Time.newInstance(23, 0, 0, 0),
    SaturdayStartTime = Time.newInstance(9, 0, 0, 0),
    SaturdayEndTime = Time.newInstance(23, 0, 0, 0),
    SundayStartTime = Time.newInstance(9, 0, 0, 0),
    SundayEndTime = Time.newInstance(23, 0, 0, 0),
    IsActive = true,
    IsDefault = true
);

However, when running the test method it fails with a caused by: System.MathException: null while running the BusinessHours.isWithin() method.

I checked the logs for both the variable assignment values and both records appear to have the same exact values. However, I only run against this exception when using the mocked records.


Variable Assignment values:

mocked record:

{
   "Id":"01m000000000001AAA",
   "MondayStartTime":32400000,
   "MondayEndTime":82800000,
   "TuesdayStartTime":32400000,
   "TuesdayEndTime":82800000,
   "WednesdayStartTime":32400000,
   "WednesdayEndTime":82800000,
   "ThursdayStartTime":32400000,
   "ThursdayEndTime":82800000,
   "FridayStartTime":32400000,
   "FridayEndTime":82800000,
   "SaturdayStartTime":32400000,
   "SaturdayEndTime":82800000,
   "SundayStartTime":32400000,
   "SundayEndTime":82800000
}

non mocked record:

{
   "Id":"01m9E0000000WfXQAU",
   "MondayStartTime":32400000,
   "MondayEndTime":82800000,
   "TuesdayStartTime":32400000,
   "TuesdayEndTime":82800000,
   "WednesdayStartTime":32400000,
   "WednesdayEndTime":82800000,
   "ThursdayStartTime":32400000,
   "ThursdayEndTime":82800000,
   "FridayStartTime":32400000,
   "FridayEndTime":82800000,
   "SaturdayStartTime":32400000,
   "SaturdayEndTime":82800000,
   "SundayStartTime":32400000,
   "SundayEndTime":82800000
}

Does anyone have an idea of what might be causing this issue? Thanks in advance for the help!

2 Answers 2

2

BusinessHours.isWithin uses data from the BusinessHours record stored in the database. Since you mocked the ID, it's not a real record, so when it tries to figure out the holidays, you'll end up with complications. In fact, running this code in execute anonymous has the same error, which proves it's not just a unit test problem.

You'll see that the line of code that throws the error is Class.System.BusinessHours.isWithin: line 30, column 1. This is within the BusinessHours system library class. I guess you could call it a bug in the system library, but the net result is that you cannot create a fake Id for a BusinessHours that will be used in the standard system library. You need a real record to work with.

This is often true whenever an Id is needed in any system library call, when performing DML, or when performing a SOQL query to retrieve records by Id.

1
  • Ah, shoot. I was looking at this problem from the wrong perspective as I thought the issue was related to the mocking itself. Thank you for the insights! Commented Dec 23, 2021 at 13:55
2

You could resolve the issue as pointed out by sfdcfox by creating a BusinessHoursService with an exposed isWithin method.

Then your testmethod could inject a mock BusinessHoursService that returned a true/false as you chose for testmethod purposes. That is, use the same pattern as used by mocking HttpCallouts where you are injecting a mock callout object.

  • The production service would use the builtin BusinessHours.isWithin method that relies on org data

You must log in to answer this question.

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