Introducing the Selector factory

The last chapter introduced the concept of a Domain factory, which was used to dynamically construct Domain class instances implementing a common Apex Interface in order to implement the compliance framework.

The following code is used in the ComplianceService.verify method's implementation, making no reference at all to a Selector class to query the records needed to construct the applicable Domain class:

fflib_SObjectDomain domain =
  Application.Domain.newInstance(recordIds);

So, how did the Domain factory retrieve the records in order to pass them to the underlying Domain class constructor? The answer is that it internally used another factory implementation called the Selector factory.

As with the Domain factory, the Selector factory resides within the Application class as a static instance, exposed via the Selector static class member, as follows:

public class Application 
{
  // Configure and create the SelectorFactory for this Application
  public static final fflib_Application.SelectorFactory Selector = 
    new fflib_Application.SelectorFactory(
      new Map<SObjectType, Type> {
        Team__c.SObjectType =>TeamsSelector.class,
        Race__c.SObjectType =>RacesSelector.class,
        Car__c.SObjectType =>CarsSelector.class,
        Driver__c.SObjectType =>DriversSelector.class,
        Contestant__c.SObjectType => ContestantsSelector.class });

  // Configure and create the DomainFactory for this Application
  public static final fflib_Application.DomainFactory Domain = 
    new fflib_Application.DomainFactory(
      Application.Selector,
      // Map SObjectType to Domain Class Constructors 
      new Map<SObjectType, Type> {
        Team__c.SObjectType =>Teams.Constructor.class,
        Race__c.SObjectType =>Races.Constructor.class,
        Car__c.SObjectType =>Cars.Constructor.class,
        Driver__c.SObjectType =>Drivers.Constructor.class,
        Contestant__c.SObjectType =>
          Contestants.Constructor.class});
}

Notice that the Selector factory is passed to the Domain factory in the preceding example. The following sections outline the methods on the factory and relevant use cases.

SelectorFactory methods

The SelectorFactory class has two methods on it: newInstance and selectById. The following code illustrates both these methods by showing two equivalent usage examples to retrieve records given a set of IDs:

List<Contestant__c> contestants = 
  Application.Selector.selectById(contestantIds); 
List<Contestant__c> contestants = 
  Application.Selector.newInstance(Contestant__c.SObjectType)
  .selectSObjectsById(contestantIds); 

As you can see from the preceding code, the selectById method provides a shortcut to access the generic selectSObjectById method from the fflib_ISObjectSelector interface and as seen earlier in this chapter is implemented by the fflib_SObjectSelector base class. As such all Selector classes are guaranteed to provide it. It offers a cleaner way of querying records in the standard way without having to know the Apex class name for the Selector. This effectively is how the Domain Factory can dynamically instantiate a Domain class instance loaded with records on behalf of the developer.

Note

The method internally uses Id.getSObjectType (on the first ID that is passed in) to look up the Selector class through the map defined previously and instantiate it (via Type.newInstance).

You would use the newInstance method instead of just instantiating directly via the new operator in the Selector class when you are writing generic code which handles different types of objects. In other cases you can continue to instantiate Selector classes in the normal manner using the new operator.

Writing tests and the Selector layer

When writing tests specifically for a Selector class method, the process is almost as per the standard Apex testing guidelines; insert the data you need to support the queries, call the Selector methods, and assert the results returned. You can review some of the Selector tests included in this chapter.

Tip

If you have implemented Selector methods that return QueryLocator instances (for use by Batch Apex callers), you can still assert the results of these methods. Use the iterator method to obtain QueryLocatorIterator, then call the next and hasNext methods to return the results to pass to your assert statements.

Of course, other Apex tests around the Controllers, Batch Apex, Domain, and Service layers might also invoke the Selector methods indirectly, thus providing code coverage, but not necessarily testing every aspect of the Selector classes.

Tip

Try to ensure that your Apex tests test the layers and functional components of the application as much as possible in isolation to ensure that the existing and future callers don't run into issues.

As highlighted previously, often writing more isolated Apex tests can be made harder due to the fact that the code being tested often requires records to be set up in the database. By leveraging the Selector factory option described earlier, a mocking approach can be taken to the Selector methods, which can help make writing more isolated and varied component or class level tests easier. We will revisit this topic in a later chapter.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.219.191.233