1

I've written an Apex job that makes use of some JobScience objects. I'm having a problem with creating a new JobScience Job Location object in an Apex test class. I can successfully create and insert the object, but what happens is there is a process that is called from within the managed package for that insert (trigger or otherwise) that attempts to make a callout to their Geolocation service which is a violation in Apex test classes (no callouts allowed). My guess is because the object contains a Geolocation field. I've tried to mock this callout (which I really can't do because it's in their namespace), I've tried to pre-populate the Geolocation field (just Lat and Lng) via a call to a mock Geolocation service, and verified that the values are indeed there, to see if that would prevent their callout from happening, but that didn't work either.

Has anyone ever run into this specific case with JobScience Job Locations inside of test classes (or anything similar when working with other managed objects)? I have no idea how to work around this and, unfortunately, Job Location is a required object for this test. We've reached out to their support but they are not able to help us (for a myriad of reasons, we'll just leave it at that).

Thanks for any an all help!

6
  • It's going to be difficult to get an answer to this because it's a managed package, but a few things you can try. See if there's a means of setting an HTTP mock in the package (see here: salesforce.stackexchange.com/questions/172435/…). You can also try mocking the objects entirely either using JSON to construct the JobScience object or mocking the JobScience objects outright by using a stand-in object. Without seeing your code it's difficult to tell how vital the JobScience object is to the Apex job.
    – nbrown
    Feb 25, 2020 at 20:47
  • 1
    for the code-under-test, do you need to update any records in the managed package? or just retrieve them for use within your code-under-test?
    – cropredy
    Feb 25, 2020 at 22:48
  • Thanks @nbrown. There isn't much to the code, really. The Apex job queries Placements so that's what's tested, the other objects are created because the hierarchy needs to be in place before I can even create a Placement. I tried to mock the callout but, as was stated & in docs, you can't mock a call that lives in a separate namespace unless you mock it from said ns. I couldn't find any exposed mocks in the JS classes. This object isn't necessary to my process, but it's required to create a Job (needed for Placements). I'll try mocking the Job Location object and see what I can get working. Feb 26, 2020 at 21:49
  • Thanks @cropredy. See my response to nbrown for more detail. I'm merely creating an object hierarchy so I can create some Placement objects, which are the focus of my test. Placements require Jobs and Applications, Jobs (in this org) require Job Locations, and there are other dependencies below that. My next move is to see if I can mock the Job Location object so I can work around the callout that is happening when the Job Location is inserted. Feb 26, 2020 at 21:56
  • 1
    the package (github) by mattaddy Sobject Fabricator is ideal for this -- I use it all the time
    – cropredy
    Feb 26, 2020 at 22:03

1 Answer 1

0

The general approach for mocking otherwise non-creatable SObjects depends on the scope you need the mocked objects for:

Option 1 - Code-Under-Test merely needs to fetch the SObjects

Preconditions

  • No DML required against the fetched objects

Solution

  • Wrap the fetch of the Sobjects into a Selector class (e.g. JobsSelector )
  • Dependency inject a mock implementation of the selector class into the code-under-test. ApexMocks is useful to do this but there are other techniques as well by passing in a mock implementation to the code-under-test's selector similar to the way HttpCalloutMock is used.
  • Have the mock selector class return mocked SObjects using the JSON.deserialize technique. A nice library that does this is SObject_Fabricator by @mattaddy

Option 2 - Code-Under-Test needs to fetch and update the SObjects

Preconditions

  • DML required against the fetched objects

Solution

  • Wrap the fetch of the Sobjects into a Selector class (e.g. JobsSelector ).
  • Wrap the DML statements into a new class using the Unit Of Work pattern such as in Trailhead Unit of Work Pattern. In effect, you registerNew(..) or registerDirty(..) Sobjects that are passed to the unit of work object.
  • Dependency inject a mock implementation of the selector class and unit of work class into the code-under-test. ApexMocks is again especially useful to do this.
  • Have the mock selector class return mocked SObjects using the JSON.deserialize technique. A nice library that does this is SObject_Fabricator by @mattaddy
  • Have the unit test verify that your calls to registerNew and registerDirty are what you expect to have happen (i.e., you constructed/modified the proper sobjects -- note no DML is actually done as you have mocked the unit of work)

Notes

  1. ApexMocks is a layer around the StubAPI and adheres to the Mockito library as used in Java. There is a learning curve here but there are resources on the GitHub Readme as well as here on Stackexchange.
1
  • Fantastic, thanks! Mar 6, 2020 at 19:14

You must log in to answer this question.

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