Every Selector layer class you create should at least implement the following methods for it to work as anticipated.
//Selector layer classes should all use the inherited sharing keyword so that the caller //determines to context it operates in.
//It should also always extend the fflib_SObjectSelector so it can inherit that classes //methods and functionality.
public inherited sharing class Contact_Selector extends fflib_SObjectSelector
{
public Contact_Selector(){
/*This is calling the fflib_SObjectSelector classes constructor and setting
the following booleans:
1) If the selector queries should use field sets
2) If you would like to enforce CRUD security
3) If you would like to enforce FLS
4) If you would like to sort selected fields
*/
super(false, true, true, false);
}
//Add the base fields for the object that should just be used in absolutely every
//query done by this class
public List<Schema.SObjectField> getSObjectFieldList(){
return new List<Schema.SObjectField>{
Contact.Id,
Contact.Name,
Contact.FirstName,
Contact.LastName
};
}
//Allows you to easily get the object type for the object being queried by this class
public Schema.SObjectType getSObjectType(){
return Contact.SObjectType;
}
//Allows you to create a query that selects records by a set of ids (basically adds
//the WHERE Id IN :ContactIds to the query)
public List<Contact> selectById(Set<Id> contactIds){
return (List<Contact>) selectSObjectsById(contactIds);
}
}
The fflib_SObjectSelector Constructor Parameters and what each of them mean
When you create a Selector class that extends the fflib_SObjectSelector class you have the option to send some parameters to its constructor that determine how to the selector class functions. They are the following (in order of parameters passed to the constructor):
1) Would you like to allow your class to use field sets when building the initial query fields for your selector layer class? By default this parameter is set to false.
2) Would you like to enforce CRUD (Object level create, read, update, delete) security on your selector layer class? By default this parameter is set to true.
3) Would you like to enforce FLS (Field level security) on your selector layer class? By default this parameter is set to false.
4) Would you like your selected fields in your query to be sorted alphabetically when your query is created (this is literally just a sort call on a list of strings in the code)? By default this parameter is set to true.
If you would like to alter any of these settings for your selector class you can do the following:
public inherited sharing class Contact_Selector extends fflib_SObjectSelector
{
//In our selector classes constructor we are calling the fflib_SObjectSelector using the super() call
//and setting out parameters.
public Contact_Selector(){
//This is completely optional. If you like the defaults listed above you do not have to call the super class constructor at all.
super(false, true, true, false);
}
}
Note that this is completely optional, if you like the default behavior listed above, just don’t bother calling the super method and overriding them!
How to set the default field selection for your Selector Class
One of the biggest benefits of the selector layer is selected field consistency in your queries. If 99% of the time you are querying for the subject field on your Case object, why not just query for it by default without ever thinking about it again right?? Well the getSObjectFieldList method that you implement in your Selector classes does just that. Here’s how to implement that method in your selector:
public List<Schema.SObjectField> getSObjectFieldList(){
//Note that this is using concrete references to the fields, not dynamic soql (here at
//least). This is to ensure the system knows
//your code is dependent on these fields so you don't accidentally delete them some
//day.
return new List<Schema.SObjectField>{
//In this list, place every field you would like to be queried for by
//default when creating a query
//with your selector class.
Contact.Id,
Contact.Name,
Contact.FirstName,
Contact.LastName
};
}
If you choose to enable field sets to allow for default field selection for your selector class, you can implement the following method to select fields from the field set to be included in your queries:
public override List<Schema.FieldSet> getSObjectFieldSetList(){
return new List<Schema.FieldSet>{SObjectType.Case.FieldSets.CaseFieldSetForSelector};
}
The major benefit of using the field sets for query fields is you can add new fields on the fly without adding extra code. This becomes super important if you’re building a managed package.
How to set your default OrderBy clause in your Selector Class
By default all Selector Layer Classes that extend the fflib_SObjectSelctor are ordered by the Name field (if the name field isn’t available on the queried object it defaults to CreatedDate). If that’s kewl with you, no need to override it, but if you’d prefer the default sort order for your select class be different then you just need to override the following method like so:
public override String getOrderBy(){
return 'Subject';
}
If you wanted to order by multiple fields you would just do the following (basically just create a comma separated list in the form of a string):
public override String getOrderBy(){
return 'Subject, Name, CustomField__c, CustomLookup__r.Name';
}
The fflib_QueryFactory class and Custom Queries
Chances are you’re gonna wanna query something that’s not immediately available via the fflib_SObjectSelect class, well lucky for you the fflib_QueryFactory class is here just for that! Here is an example of a custom query via the use of the fflib_QueryFactory class (a list of all available query factory methods are at the bottom of this wiki article).
//This allows us to select all new cases in the system using the QueryFactory in //fflib_SObjectSelector
public List<Case> selectNewCases(){
return (List<Case>) Database.query(newQueryFactory().
selectField(Case.Origin).
setCondition('Status = \'New\'').
setLimit(1000).
toSOQL());
}
There are also tons of other methods that allow you to add offsets, subselects, set ordering and more (outlined in the method cheat sheet section).
How to Do Sub-Select Queries (Inner Queries)
There’s a kinda handy way to do sub-select queries by using the fflib_QueryFactory class. You can use it in your selector class’s methods as outlined below:
//Pretend this method exists in a Case_Selector class
public List<Case> innerQueryExample(){
//Using this Case_Selectors newQueryFactory method that it inherits from the
//fflib_SObjectSelector class it extends
fflib_QueryFactory caseQueryFactory = newQueryFactory();
//Creating a new instance of our Task_Selector class and using the
//addQueryFactorySubselect method to add the task query as a
//inner query for the caseQueryFacorty
fflib_QueryFactory taskSubSelectQuery = new
Task_Selector().addQueryFactorySubselect(caseQueryFactory);
//Querying for our data and returning it.
return (List<Case>) Database.query(caseQueryFactory.toSOQL());
}
How to do Aggregate Queries
There’s not really a built-in method in either the fflib_SObjectSelector or the QueryFactory class to deal with this. So you just deal with aggregate queries by building a method in your Selector Class in the following way:
public List<AggregateResult> selectAverageTacosPerTacoBell(){
List<AggregateResult> tacoData = new List<AggregateResult>();
for(AggregateResult result: [SELECT Id, AVG(Tacos_Sold__c) avgTacos FROM Taco_Bell__c
GROUP BY Taco_Type__c]){
tacoData.add(result);
}
return tacoData;
}
The fflib_SObjectSelector Class methods Cheat Sheet
While there are many other methods within the fflib_SObjectSelector class below are the methods most commonly utilized in implementations.
1) getSObjectName()_ – Returns the name of the object that your select was built for.
2) selectSObjectsById(Set<Id> idSet) – Returns a query that selects all the records in your id set. It constructs a query based on the fields you declare in your selector class’s getSObjectFieldsList method and orders them by whatever is represented in the m_orderBy variable.
3) queryLocatorById(Set<Id> idSet) – This method is basically the same as the selectSObjectsById method except that it returns a query locator instead. This should be leveraged for batch classes that need query locators.
4) newQueryFactory – This method returns a new instance of the fflib_QueryFactory class and uses your selector classes fields listed in the getSObjectFieldsList method and orders them by whatever you set the default orderby to in your selector class.
5) addQueryFactorySubselect(fflib_QueryFactory parentQueryFactory) – This method basically just creates a subselect query (an inner query) for the “parentQueryFactory” and then returns the parent query with a subselect query that represents the query for your objects selector class (more info on how this method works in the sub-select query section in this wiki article).
The fflib_QueryFactory Class methods Cheat Sheet
While there are many other methods within the fflib_QueryFactory class below are the methods most commonly utilized in implementations.
1) assertIsAccessible() – This method checks to see if the running user can actually read to object this selector was built for.
2) setEnforceFLS(Boolean enforce) – This method determines whether or not to enforce field level security on the query you are running.
3) setSortSelectFields(Boolean doSort) – If you would like the list of fields selected to be selected in alphabetical order, you can use this method to make your selected fields be selected in alphabetical order.
7) setCondition(String conditionExpression) – Use this method to set the conditions for your query (basically you are setting the WHERE clause in your query. Do NOT add the WHERE to the string you pass into to this method).
10) addOrdering(Ordering o) – Sets up an ORDER BY clause for your query. You need to build an fflib_QueryFactory.Ordering object to pass to this method. There are a ton of ordering method permutations in this class, so definitely check them all out.
11) subselectQuery(String relationshipName) – Sets up a subquery for the query. You need to pass in a string representation of the relationship fields developer name to this method.
12) toSOQL() – Takes the fflib_QueryFactory you’ve just built and turns it into an actual string representation of the query that you can use in a Database.query() call.
13) deepClone() – Creates a clone of your fflib_QueryBuilder query in case you’d like an easy way to generate another permutation of this query without rebuilding the whole thing.
Unit Testing, is a way to test the logic in one class and ONLY one class at a time. Most classes in your system at some point do one of the following:
1) Call to another class to get some work done. 2) Query the database directly in the class. 3) Do DML transactions directly in the class.
However, in unit testing, we ideally don’t want to do any of those things, we don’t care if the querying or the DML transactions or the calls to those other classes work, because what we want to test is that the logic of our class works in every theoretical permutation we can think of AND THAT’S IT! We just want to know if our logic, that we designed for this one class actually works as we anticipate it to work.
You might be thinking, “How is that possible? We need those queries and those dml statements and those classes to successfully run our code!”. Well that my friends is simply not true. With the implementation of separation of concerns and by leveraging one of the many available mocking frameworks we can fake all of those things to build true unit tests.
When Should I use Unit Testing?
Just because you are leveraging unit testing doesn’t mean there still isn’t a need for integration tests (more on that below), so when should you do Unit Tests in favor of Integration tests? It’s a pretty simple answer. The logic in your class’s code could have 40+ paths it could take… maybe even 100… The code in your class could have logic that runs when your code fails, logic that runs when your codes successful, logic that runs when someone creates a $200,000,000 opportunity as opposed to a $2,000 opportunity. There could be so many paths. We DO NOT need an integration test for every single one of those paths. It could take 20+ minutes to run integration tests for all those paths whereas unit testing them could take just seconds. As your codebase grows, if you didn’t make these unit tests your test class runs to deploy to prod could take hours… maybe days… we don’t want that homie. So when do you unit test? You unit test to test the bajillions of permutations of your class’s logic. When do we choose integration tests?? Keep reading. You’ll find out below.
An additional benefit to unit testing/mocking responses is testing hard to test or impossible to test error catching scenarios. One common scenario that I find myself frequently building error catching around is record locking… but how on earth can you test that with real data at run time? It’s borderline impossible, however unit testing makes testing for errors a breeze. It’s so easy you’ll cry, lol, the dream of 100% code coverage can go from just a dream to a very real and easily obtainable thing with unit tests and mocking.
What is Integration Testing?
Integration testing is when you test your code from point A all the way to point Z. What I mean by that is, you actually have your code in your test classes doing SOQL statements, DML transactions, calling the other classes it depends on, etc. Basically your code is truly calling all the real logic from beginning to end, no mocking or fake return results anywhere. Integration testing is what 90%+ of Salesforce orgs seem to do 100% of the time and that is one dangerous game to play. The majority of your tests should not be integration tests… maybe like 20% of them or so. If 100% of your test classes are integration tests, over time you’ll suffer from long test execution and deployment times (or alternatively poorly tested code to reduce those times). If you’ve ever been stuck in a 6+ hour deployment, I think you know what I mean… and what if one test fails during that deploy?… it really hurts, lol. Please, don’t get me wrong though, you can not replace integration tests with unit tests, they are of equal importance, it’s just important that you only use integration tests when needed.
When Should I use Integration Testing?
All apex classes should have some level of integration testing. I like to write somewhere around 20% of my tests as integration tests and 80% of my tests for a class as unit tests. Typically I will, for each class that has dependencies (classes that the class I’m currently testing calls) write two integration tests for each dependency. One integration test that tests a successful path through my classes code and its dependencies and another that tests failures. This may be, in some peoples opinion, overkill, but I personally feel that it’s not an enormous amount of overhead (typically) and it gives me some piece of mind that all of the classes my class I’m testing depends on still operate well with it. So, when to use integration testing? In my opinion, in every test class, but use them sparingly, use them to check that your transactions between classes still work, don’t use them to test every logical path in your class’s code. That will spiral out of control.
How does Unit Testing fit into Separation of Concerns?
The answer to this is simple, without Separation of Concerns, there is no unit testing, it just simply isn’t possible. To unit test you need to be able to create stub (mock) classes to send into your class you are testing via dependency injection (or through the use of a factory, more on this in the next section). If all of your concerns are in one class (DML transactions, SOQL queries, service method, domain methods, etc) you cannot fake anything. Let’s take a look at a couple examples to illustrate this problem:
Unit Testing a class with SoC Implemented
//This is the class we would be testing
public with sharing class SoC_Class
{
private DomainClass domainLayerClass;
private SelectorClass selectorLayerClass;
public SoC_Class(){
//This is calling our private constructor below
this(new domainLayerClass(), new selectorLayerClass());
}
//Using a private constructor here so our test class can pass in dependencies we would
//like to mock in our unit tests
@TestVisible
private SoC_Class(DomainClass domainLayerClass, SelectorClass selectorLayerClass){
this.domainLayerClass = domainLayerClass;
this.selectorLayerClass = selectorLayerClass;
}
public List<Case> updateCases(Set<Id> objectIds){
//Because of our dependency injection in the private constructor above we can
//mock the results of these class calls.
List<Case> objList = selectorLayerClass.selectByIds(objectIds);
if(!objList.isEmpty()){
List<Case> objList = domainLayerClass.updateCases(objList);
return objList;
}
else{
throw new Custom_Exception();
}
}
}
//This is the class that we build to unit test the class above
@IsTest
public with sharing class SoC_Class_Test
{
@IsTest
private static void updateCases_OppListResults_UnitTest(){
//Creating a new fake case id using the IdGenerator class. We do this
//to avoid unnecessary dml insert statements. Note how the same id is used
//everywhere.
Id mockCaseId = fflib_IDGenerator.generate(Case.SObjectType);
//Creating a set of ids that we pass to our methods.
Set<Id> caseIds = new Set<Id>{mockCaseId};
//Creating the list of cases we'll return from our selector method
List<Case> caseList = new List<Case>{new Case(Id = mockCaseId, Subject = 'Hi',
Status = 'New', Origin = 'Email')};
List<Case> updatedCaseList = new List<Case>{new Case(Id = mockCaseId, Subject
= 'Panther', Status = 'Chocolate', Origin = 'Email')};
//Creating our mock class representations by using the ApexMocks class's mock
//method and passing it the appropriate class type.
fflib_ApexMocks mocks = new fflib_ApexMocks();
DomainClass mockDomain = (DomainClass) mocks.mock(DomainClass.class);
SelectorClass mockSelector = (SelectorClass) mocks.mock(SelectorClass.class);
//After you've setup your mocks above, we need to stub (or setup the expected
//method calls and what they would return.
mocks.startStubbing();
//This is the actual selectByIds method that we call in the
//createNewOpportunities method that we are testing
//Here we are setting up the fake return result it will return.
mocks.when(mockSelector.selectByIds(caseIds)).thenReturn(caseList);
mocks.when(mockDomain.updateCases(caseList)).thenReturn(updatedCaseList);
//When you are done setting these up, DO NOT FORGET to call the stopStubbing
//method or you're gonna waste hours of your life confused
mocks.stopStubbing();
Test.startTest();
//Passing our mock classes into our private constructor
List<Case> updatedCases = new SoC_Class(mockDomain,
mockSelector).updateCases(caseIds);
Test.stopTest();
System.assertEquals('Panther', updatedCases[0].Subject,
'Case subject not updated');
//Verifying this method was never called, we didn't intend to call it, so
//just checking we didn't
((Cases)mocks.verify(mockDomain, mocks.never().description('This method was
called but it shouldn\'t have been'))).createOpportunities();
//Checking that we did indeed call the createTasks method as expected.
((Cases)mocks.verify(mockDomain)).updateCases(caseList);
}
}
Above you can see we are passing in fake/mock classes to the class we are testing and staging fake return results for the class methods we are calling. Thanks to separating out our concerns this is possible. Let’s take a look at how impossible this is without SoC in place.
Unit Testing a class without SoC Implemented
//This is the class we would be testing
public with sharing class No_SoC_Class
{
public List<Case> updateCases(Set<Id> objectIds){
//Because of our dependency injection in the private constructor above we can
//mock the results of these class calls.
List<Case> objList = [SELECT Id, Name FROM Case WHERE Id IN: objectIds]
if(!objList.isEmpty()){
for(Case cs: objList){
cs.Subject = 'Panther';
cs.Status = 'Chocolate';
}
update objList;
return objList;
}
else{
throw new Custom_Exception();
}
}
}
@IsTest
public with sharing class No_SoC_Class_Test
{
@TestSetup
private static void setupData(){
Case newCase = new Case(Subject = 'Hi', Status = 'New', Origin = 'Email');
insert newCase;
}
@IsTest
private static void updateCases_CaseListResults_IntegrationTest(){
Set<Id> caseIds = new Map<Id, SObject>([SELECT Id FROM Case]).keySet();
List<Case> updatedCases = new No_SoC_Class().updateCases(caseIds);
System.assertEquals('Panther', updatedCases[0].Subject, 'Case subject not
updated');
}
}
You can see above we did no mocking… it wasn’t possible, we had no way of passing in fake/mock classes to this class at all so we had to do an integration test where we create real data and update real data. This test will run considerably slower.
How do I transition my Existing Code to start leveraging SoC so I can use Unit Test Mocking?
It’s not a simple path unfortunately, there is a lot of work ahead of you to start this transition, but it is possible. The key is to start small, if you are a tech lead the first thing you need to do is find the time to train your devs on what SoC and mocking is and why you would use it. It’s critical they understand the concepts before trying to roll something like this out. You cannot do everything as a lead even if you’d like to, you need to build your team’s skillset first. If you aren’t a lead, you first need to convince your lead why it’s critical you start taking steps in that direction and work to get them onboard with it. If they ignore you, you need a new lead… After accomplishing either the above you should do the following:
1) Frame your situation in a way that the business arm of your operation understands the importance of altering your code architecture to leverage SoC and unit testing. This is typically pretty easy, just inform them that by spending a few extra points per story to transition the code you are going to gain more robust testing (resulting in less manual tests) and that the code will become more flexible over time, allowing for easier feature additions to your org. Boom, done, product owner buy in has been solidified. Ok, lol, sometimes it’s not quite this easy, but you know your business people, give them something they won’t ignore, just be careful to not make yourself or your team sound incompetent, don’t overcommit and make promises you can’t keep and frame it in words business people understand (mostly dollar signs).
2) Start small, take this on a story by story basis. Say you have a new story to update some UI in your org, with business owner buy-in, tack on a few extra points to the story to switch it to start using SoC and Unit Testing. Then, MAKE SURE YOUR TESTS ARE INCREDIBLE AND YOU TRUST THEM! I say this because, if your tests are incredible you never have to ask for permission again… I mean think about it, wtf does the average business person know about code. As long as I don’t introduce any new bugs I could change half the code base and they’d never even know. If your tests are golden, your ability to change on a whim is as well. Make those test classes more trustworthy than your dog (or cat I guess… but I wouldn’t trust a cat).
3) Over time, your transition will be done… it might take a year, it might take 5 years, depends on how busted your codebase was to begin with. Hopefully, by the time you are done, you have an extremely extensible codebase with tests you can trust and you never have to ask for permission to do a damn thing again.
Apex Mocks is unit test mocking framework for Apex that was inspired by the very popular Java Mockito framework. The Apex Mocks framework is also built using Salesforce’s Stub API which is a good thing, there are mocking frameworks in existence that do not leverage the Stub API… you shouldn’t use them as they are considerably less performant. In fact, as a remnant of the past, Apex Mocks still has an option to not use the Stub API, don’t use it.
To make this super simple, Apex Mocks is an excellent framework that allows you to not only create mock (fake) versions of your classes for tests, but also allows you to do a number of other things like create mock (fake) records, verify the amount of times a method was called, verify method call order and lots more. There is not another mocking framework for the Apex language that is anywhere near as robust.
Do you have to use the Apex Common Library to use Apex Mocks?
While you don’t have to use the Apex Common Library to use Apex Mocks, they are built to work extremely well together. Without the use of the Apex Common Library you will need to ensure that all of your classes utilize dependency injection. While this isn’t a massive feat, it’s something you have to be cognizant of. If you decide to use the Apex Common library and leverage the the fflib_Application class factory you can leverage the setMock methods to avoid needing to setup all your classes using dependency injection. It’s pretty convenient and makes the whole situation a bit easier. We’ll take a look at both methods below:
Using Apex Mocks without Apex Common Example
//Class we're testing
public with sharing class SoC_Class
{
private DomainClass domainLayerClass;
private SelectorClass selectorLayerClass;
public SoC_Class(){
//This is calling our private constructor below
this(new domainLayerClass(), new selectorLayerClass());
}
//THE MAJOR DIFFERENCE IS HERE! We're using a private constructor here so our test class can pass in dependencies we would
//like to mock in our unit tests
@TestVisible
private SoC_Class(DomainClass domainLayerClass, SelectorClass selectorLayerClass){
this.domainLayerClass = domainLayerClass;
this.selectorLayerClass = selectorLayerClass;
}
public List<Case> updateCases(Set<Id> objectIds){
//Because of our dependency injection in the private constructor above we can mock the results of these class calls.
List<Case> objList = selectorLayerClass.selectByIds(objectIds);
if(!objList.isEmpty()){
List<Case> objList = domainLayerClass.updateCases(objList);
return objList;
}
else{
throw new Custom_Exception();
}
}
}
//Test class
@IsTest
public with sharing class SoC_Class_Test
{
@IsTest
private static void updateCases_OppListResults_UnitTest(){
Id mockCaseId = fflib_IDGenerator.generate(Case.SObjectType);
Set<Id> caseIds = new Set<Id>{mockCaseId};
List<Case> caseList = new List<Case>{new Case(Id = mockCaseId, Subject = 'Hi', Status = 'New', Origin = 'Email')};
List<Case> updatedCaseList = new List<Case>{new Case(Id = mockCaseId, Subject = 'Panther', Status = 'Chocolate', Origin = 'Email')};
fflib_ApexMocks mocks = new fflib_ApexMocks();
DomainClass mockDomain = (DomainClass) mocks.mock(DomainClass.class);
SelectorClass mockSelector = (SelectorClass) mocks.mock(SelectorClass.class);
mocks.startStubbing();
mocks.when(mockSelector.selectByIds(caseIds)).thenReturn(caseList);
mocks.when(mockDomain.updateCases(caseList)).thenReturn(updatedCaseList);
mocks.stopStubbing();
Test.startTest();
//THE MAJOR DIFFERENCE IS HERE! We are passing in our mock classes we created above to the private constructor that is only
//visible to tests to leverage dependency injection for mocking.
List<Case> updatedCases = new SoC_Class(mockDomain, mockSelector).updateCases(caseIds);
Test.stopTest();
System.assertEquals('Panther', updatedCases[0].Subject, 'Case subject not updated');
((Cases)mocks.verify(mockDomain, mocks.never().description('This method was called but it shouldn\'t have been'))).createOpportunities();
((Cases)mocks.verify(mockDomain)).updateCases(caseList);
}
}
If you take a look at the above SoC_Class class you can see that we are leveraging the concept of dependency injection to allow our SoC_Class_Test test class the ability to inject the mock classes during our unit test. This is the key difference. All of your classes MUST LEVERAGE DEPENDENCY INJECTION to be able to incorporate unit test mocking into your codebase. Now let’s take a look at how to do the same thing using the Apex Common Library and the fflib_Application class.
Using Apex Mocks with Apex Common Example
//Example Application factory class. This is only here because it is referenced in the classes below.
public with sharing class Application
{
public static final fflib_Application.UnitOfWorkFactory UOW =
new fflib_Application.UnitOfWorkFactory(
new List<SObjectType>{
Case.SObjectType,
Contact.SObjectType,
Account.SObjectType,
Task.SObjectType}
);
public static final fflib_Application.ServiceFactory service =
new fflib_Application.ServiceFactory(
new Map<Type, Type>{
Task_Service_Interface.class => Task_Service_Impl.class}
);
public static final fflib_Application.SelectorFactory selector =
new fflib_Application.SelectorFactory(
new Map<SObjectType, Type>{
Case.SObjectType => Case_Selector.class,
Contact.SObjectType => Contact_Selector.class,
Task.SObjectType => Task_Selector.class}
);
public static final fflib_Application.DomainFactory domain =
new fflib_Application.DomainFactory(
Application.selector,
new Map<SObjectType, Type>{Case.SObjectType => Cases.Constructor.class,
Contact.SObjectType => Contacts.Constructor.class}
);
}
//Class we're testing
public with sharing class Task_Service_Impl implements Task_Service_Interface
{
public void createTasks(Set<Id> recordIds, Schema.SObjectType objectType)
{
//THE MAJOR DIFFERENCE IS HERE! Instead of using constructors to do dependency injection
//we are initializing our classes using the fflib_Application factory class.
fflib_ISObjectDomain objectDomain = Application.domain.newInstance(recordIds);
fflib_ISObjectSelector objectSelector = Application.selector.newInstance(objectType);
fflib_ISObjectUnitOfWork unitOfWork = Application.UOW.newInstance();
List<SObject> objectsThatNeedTasks = new List<SObject>();
if(objectSelector instanceof Task_Selector_Interface){
System.debug('Selector an instance of tsi');
Task_Selector_Interface taskFieldSelector = (Task_Selector_Interface)objectSelector;
objectsThatNeedTasks = taskFieldSelector.selectRecordsForTasks();
}
else{
System.debug('Selector not an instance of tsi');
objectsThatNeedTasks = objectSelector.selectSObjectsById(recordIds);
}
if(objectDomain instanceof Task_Creator_Interface){
System.debug('Domain an instance of tci');
Task_Creator_Interface taskCreator = (Task_Creator_Interface)objectDomain;
taskCreator.createTasks(objectsThatNeedTasks, unitOfWork);
}
try{
unitOfWork.commitWork();
}
catch(Exception e){
throw e;
}
}
}
public with sharing class Task_Service_Impl_Test
{
@IsTest
private static void createTasks_CasesSuccess_UnitTest(){
Id mockCaseId = fflib_IDGenerator.generate(Case.SObjectType);
Set<Id> caseIds = new Set<Id>{mockCaseId};
List<Case> caseList = new List<Case>{new Case(Id = mockCaseId, Subject = 'Hi', Status = 'New', Origin = 'Email')};
fflib_ApexMocks mocks = new fflib_ApexMocks();
fflib_SObjectUnitOfWork mockUOW = (fflib_SObjectUnitOfWork) mocks.mock(fflib_SObjectUnitOfWork.class);
Cases mockCaseDomain = (Cases) mocks.mock(Cases.class);
Case_Selector mockCaseSelector = (Case_Selector) mocks.mock(Case_Selector.class);
mocks.startStubbing();
mocks.when(mockCaseSelector.sObjectType()).thenReturn(Case.SObjectType);
mocks.when(mockCaseSelector.selectSObjectsById(caseIds)).thenReturn(caseList);
mocks.when(mockCaseSelector.selectRecordsForTasks()).thenReturn(caseList);
mocks.when(mockCaseDomain.sObjectType()).thenReturn(Case.SObjectType);
((fflib_SObjectUnitOfWork)mocks.doThrowWhen(new DmlException(), mockUOW)).commitWork();
mocks.stopStubbing();
//THE MAJOR DIFFERENCE IS HERE! Instead of dependency injection we are using our
//the setMock method in the fflib_Application class to set our mock class for unit tests.
Application.UOW.setMock(mockUOW);
Application.domain.setMock(mockCaseDomain);
Application.selector.setMock(mockCaseSelector);
try{
Test.startTest();
Task_Service.createTasks(caseIds, Case.SObjectType);
Test.stopTest();
}
catch(Exception e){
System.assert(e instanceof DmlException);
}
((Cases)mocks.verify(mockCaseDomain, mocks.never().description('This method was called but it shouldn\'t have
been'))).handleAfterInsert();
((Cases)mocks.verify(mockCaseDomain)).createTasks(caseList, mockUOW);
}
}
As you can see, in this example we no longer leverage dependency injection to get our mock unit tests up and running. Instead we use the setMock method available on all of the inner factory classes in the fflib_Application class to setup our mock class for our unit test. It makes things a bit easier in the long run.
Now that we’ve seen how to setup a mock class with or without Apex Common, let’s figure out all the cool things Apex Mocks has to allow you to assert your logic operated in the way you anticipated it would! We’ll start with a section on what stubbing is below!
What is Stubbing and how to Stub
Soooooo, what exactly is stubbing? Basically it’s the act of providing fake return responses for a mocked class’s methods and it’s super extra important when setting up your unit tests because without them, well frankly nothing is gonna work. So let’s check out how to do stubbing below:
Id mockCaseId = fflib_IDGenerator.generate(Case.SObjectType);
List<Case> caseList = new List<Case>{new Case(Id = mockCaseId, Subject = 'Hi', Status = 'New', Origin = 'Email')};
//Creating the mock/fake version of our case selector class
fflib_ApexMocks mocks = new fflib_ApexMocks();
Case_Selector mockCaseSelector = (Case_Selector) mocks.mock(Case_Selector.class);
//Here is where we start stubbing our fake return values from our methods that will be called by the actual class we are testing.
//You need to initialize our mock stubbing by using the mocks.startStubbing method.
mocks.startStubbing();
mocks.when(mockCaseSelector.sObjectType()).thenReturn(Case.SObjectType);
mocks.when(mockCaseSelector.selectSObjectsById(caseIds)).thenReturn(caseList);
//This is basically saying, "hey, when the method we're testing calls the selectRecordsForTasks method on our mocked case selector
//please always return this caseList."
mocks.when(mockCaseSelector.selectRecordsForTasks()).thenReturn(caseList);
mocks.stopStubbing();
//Don't forget to stop stubbing!! Very importante!
//Make sure to do your stubbing before sending your mock class to your application factory class!!!
Application.selector.setMock(mockCaseSelector);
//Doing the test of the actual method that will call those mocked class's stubbed methods above. Make sure to create the mock classes and the stubbed
//method responses for your classes before doing this test!
Test.startTest();
Task_Service.createTasks(caseIds, Case.SObjectType);
Test.stopTest();
Alright, let’s go over this a bit (and if you didn’t read the comments in the code outlined above please do!). The first thing you should know is that you should only be creating stubbed methods for methods that are actually called by the real method you are actually testing (in our case, the Task_Service.createTasks method). Now that we’ve clarified that, let’s break down one of our stubs that we built out for the methods in our mocked class. Take this stub ‘mocks.when(mockCaseSelector.selectRecordsForTasks()).thenReturn(caseList);’, what we are efficitively saying here is, when our mockCaseSelector’s selectRecordsForTasks method is called, let’s always return the caseList value. Not too complicated but maybe confusing if you’ve never seen the syntax before.
Hopefully this has helped explain the basic concept of stubbing alright, there’s more we can do with stubbing in regards to throwing fake errors, so be sure to check out the, “How to mock exceptions being thrown” section below for more information on that subject.
How to verify the class you’re actually testing appropriately called your mock class methods
If you’ve never done mocking before this might seem super weird, instead of using asserts, we need another way to verify that our code functioned as anticipated with our fake classes and return values. So what exactly do you verify/assert in your test? What we’re gonna end up doing is verify that we did indeed call the fake methods with the parameters we anticipated (or that we didn’t call them at all). So let’s take a look at how to use the verify method in the fflib_ApexMocks class to verify a method we intended to call, did indeed get called:
Id mockCaseId = fflib_IDGenerator.generate(Case.SObjectType);
//Creating a set of ids that we pass to our methods.
Set<Id> caseIds = new Set<Id>{mockCaseId};
//Creating the list of cases we'll return from our selector method
List<Case> caseList = new List<Case>{new Case(Id = mockCaseId, Subject = 'Hi', Status = 'New', Origin = 'Email')};
//Creating our mock class representations by using the ApexMocks class's mock method
//and passing it the appropriate class type.
fflib_ApexMocks mocks = new fflib_ApexMocks();
fflib_SObjectUnitOfWork mockUOW = (fflib_SObjectUnitOfWork) mocks.mock(fflib_SObjectUnitOfWork.class);
Cases mockCaseDomain = (Cases) mocks.mock(Cases.class);
mocks.startStubbing();
mocks.when(mockCaseDomain.sObjectType()).thenReturn(Case.SObjectType);
mocks.stopStubbing();
Application.UOW.setMock(mockUOW);
Application.domain.setMock(mockCaseDomain);
Test.startTest();
//Calling the method we're actually testing (this is a real method call)
Task_Service.createTasks(caseIds, Case.SObjectType);
Test.stopTest();
//THIS IS IT!!! HERE IS WHERE WE ARE VERIFYING THAT WE ARE CALLING THE CASE DOMAIN CREATE TASKS CLASS ONCE!!!
((Cases)mocks.verify(mockCaseDomain, 1)).createTasks(caseList, mockUOW);
On the very last line of the above code we are using the verify method to ensure that the createTasks method in the Cases class was called exactly one time with the caseList and mockUOW values passed to it. You might be looking at this and thinking, “But why Matt? Why would I actually care to this?”. The answer is pretty simple. Even though your code in those classes isn’t running, you still want to (really need to) verify that your code still decided to call it (or not call it), that you code didn’t call the method more times than you were anticipating, etc. Remember, the major purpose of a unit test is to test that the logic in your class is working how you anticipate it to. Verifying that methods were called correctly is extremely important. If your class calls the wrong methods at the wrong time, super ultra terrible consequences could end up taking place.
How to verify your data was altered by your class when it was sent to a mocked class (Matchers)
Whoooo that’s a long title, lol. Here’s the dealio, at least half the time the data you pass into the class you are actually testing (the one class we aren’t mocking) it will altered and then sent in to another mocked class’s method to be further processed. Chances are you’d like to verify that data was altered prior to sending it to your mocked classes method. Never fear my good ole pals, the fflib_Match class is here to help you do just that! Let’s take a look at how we can use matchers to identify what exactly was passed into our mocked class’s methods!
Id mockCaseId = fflib_IDGenerator.generate(Case.SObjectType);
List<Case> caseList = new List<Case>{new Case(
Id = mockCaseId,
Subject = 'Hi',
Status = 'New',
Origin = 'Email')};
fflib_ApexMocks mocks = new fflib_ApexMocks();
fflib_SObjectUnitOfWork mockUOW = (fflib_SObjectUnitOfWork) mocks.mock(fflib_SObjectUnitOfWork.class);
Application.UOW.setMock(mockUOW);
Test.startTest();
//Calling the method we're actually testing (this is a real method call). IN THIS METHOD WE ARE CHANGING THE CASE SUBJECTS FROM 'Hi' to 'Bye'
new Cases().changeSubject(caseList);
Test.stopTest();
//Here we are using the fflib_Match class to create a new sobject to match against to verify the subject field was actually changed in the above method //call.
List<Case> caseMatchingList = (List<Case>)fflib_Match.sObjectsWith(new List<Map<Schema.SObjectField, Object>>{new Map<SObjectField, Object>{
Case.Id => mockCaseId,
Case.Subject => 'Bye',
Case.Status => 'New',
Case.Origin => 'Email'}
});
//Here we are verifying that our unit of works registerDirty method was indeed called with the updated data we expected by using a matcher. This should //return true pending your code actually did update the cases prior to calling this method as you intended.
((fflib_ISObjectUnitOfWork)mocks.verify(mockUOW)).registerDirty(caseMatchingList);
//This also works (confusing right)... but it proves a lot less, it simply proves your method was called with that list of cases, but it doesn't prove it //updated those cases prior to calling it.
((fflib_ISObjectUnitOfWork)mocks.verify(mockUOW,1)).registerDirty(caseList);
Alright alright alright, you might be looking at this and being like, “But bruh why make a matcher at all to get this done? Why not just keep it simple and make another list of cases to represent the changes”. Fair enough question hombre, here’s the simple answer… it’s not gonna work, trust me, lol. Basically ApexMocks needs a way to internally check these events actually occurred and that matcher we setup is the key to doing that. If you wanna dive deep into how it works feel free, but that is a whole different subject we’re not gonna get into the weeds of.
So we can see, I think, that this is extremely useful in terms of verifying our logic occurred in the right order and updated our data as anticipated before calling the method in one of our mocked classes. Pretty cool, makes our unit testing that much more accurate.
There are a ton more methods in the fflib_Match class that you can leverage to do virtually whatever you can think of, there’s a list of those near the bottom of this page. Definitely check them out.
How to mock exceptions being thrown (this is THA BEST!!)
If you don’t care about time savings for test runs to get your code into production, you should pick up mocking to allow for easier exception testing at the very least. IT IS SO MUCH EASIER TO VERIFY EXCEPTIONS!!!! A magical thing that honestly can’t be beat. Tons of errors that you should rightfully handle in a ton of situations (like record locking errors) are borderline impossible to test with real data… this makes it possible. Some people out there might be like, “Hah, but I don’t even catch my exceptions why should I care?”. To that I say, time to change my guy, lol, you need to catch those bad boiz, trust me. Anywhooo, let’s get right to it! How do we mock our exceptions to make testing exceptions so simple and so glorious? Let’s checkout the code below:
Here’s an example of mocking an error when the method returns nothing:
fflib_ApexMocks mocks = new fflib_ApexMocks();
fflib_SObjectUnitOfWork mockUOW = (fflib_SObjectUnitOfWork) mocks.mock(fflib_SObjectUnitOfWork.class);
mocks.startStubbing();
//This right here is what's doing the mock error throwing!! Basically we're saying, when the commitWork method in our
//mockUOW class is called by the method we are truly testing, please throw a new DMLException.
((fflib_SObjectUnitOfWork)mocks.doThrowWhen(new DmlException(), mockUOW)).commitWork();
mocks.stopStubbing();
Application.UOW.setMock(mockUOW);
try{
Test.startTest();
//Calling the method we're actually testing (this is a real method call)
Task_Service.createTasks(caseIds, Case.SObjectType);
Test.stopTest();
}
catch(Exception e){
//Because we are throwing an exception in our stubs we need to wrap our real
//method call in a try catch and figure out whether or not it actually threw the
//exception we anticipated it throwing.
System.assert(e instanceof DmlException);
}
Here’s a similar example but with a method that returns data:
fflib_ApexMocks mocks = new fflib_ApexMocks();
Case_Selector mockCaseSelector = (Case_Selector) mocks.mock(Case_Selector.class);
mocks.startStubbing();
//These two methods must be stubbed for selectors if using apex common library
mocks.when(mockCaseSelector.sObjectType()).thenReturn(Case.SObjectType);
mocks.when(mockCaseSelector.selectSObjectsById(caseIds)).thenReturn(caseList);
//This right here is what's doing the mock error throwing!! Basically we're saying, when the selectRecordsForTasks method in our
//mockCaseSelector class is called by the method we are truly testing, please throw a new DMLException.
mocks.when(mockCaseSelector.selectRecordsForTasks()).thenThrow(new DmlException());
mocks.stopStubbing();
Application.selector.setMock(mockCaseSelector);
try{
Test.startTest();
//Calling the method we're actually testing (this is a real method call)
Task_Service.createTasks(caseIds, Case.SObjectType);
Test.stopTest();
}
catch(Exception e){
//Because we are throwing an exception in our stubs we need to wrap our real
//method call in a try catch and figure out whether or not it actually threw the
//exception we anticipated it throwing.
System.assert(e instanceof DmlException);
}
You can see that there’s a small difference between the two. For the method that actually returns data the chain of events is a bit easier to follow mocks.when(mockCaseSelector.selectRecordsForTasks()).thenThrow(new DmlException());. This basically is just saying, when we call the mock selector class’s selectRecordsForTasks class then we need to throw a new DMLException.
For the method that doesn’t return any data (a void method) the syntax is a little different ((fflib_SObjectUnitOfWork)mocks.doThrowWhen(new DmlException(), mockUOW)).commitWork(). You can see that instead of using the mocks.when(method).thenThrow(exception) setup we are now using the doThrowWhen method, which kinda combines the when(method).thenThrow(exception) into a single statement. You can also see it takes two parameters, the first is the exception you want to throw and the second is the mocked class you are attaching this exception throwing event to. Then you have to cast this mocks.doThrowWhen(exception, mockedClass) to the class type it will end up representing, wrap it in parenthesis and call the method you intend it to throw an error on. Weird setup, awesomely simple exception testing though.
Also worth noting, don’t forget to wrap methods you are truly testing (that will now throw an error) in a try catch in your test and in the catch block, assert that you are getting your exceptions throw.
How to test important method side-effects truly occured (Answering)
It is not at all uncommon to have parameters passed into a method by reference and for that method to update those parameters but not pass them back. Some people refer to this as method side effects. To truly do good unit tests however we should mock those side effects as well. That is where the fflib_Answer interface comes into play! Now, unlike most things I’ve written about in this series, there is a blog post by Eric Kintzer that already exists for this apex mocks topic that is excellent and well… frankly I don’t need to re-invent the wheel here. Please go check out how to do Answering with Apex Mocks here. .
How to check method call order
Sometimes when you are doing unit tests it’s extremely important to verify the order in which your methods were called. Maybe, depending on what data your method receives your mock class’s methods could be called in varying orders. It’s best to check that the code is actually doing that! If you do need to check for that in your code, no worries, that is why the fflib_InOrder class exists! Thankfully this is yet another area I really don’t need to cover again in this guide as a good blog post exists covering this topic as well! If you need to check method ordering in your unit testing, please check out the blog post here!
Apex Mocks Counters (Counting method calls and adding descriptions)
Counters counters counters… they’re one of the simplest things to learn thankfully and also very useful! Basically you might want to know how many times a method in a mock class was called by the class you are currently unit testing. It helps to verify the logic in your code is only calling classes in the way you intended for it to call it. The syntax is pretty simple so lets get to learninnnnnnnn.
When we are verifying method calls (as discussed in one of the above sections) we do the following:
What if we wanna check whether the code operated only once though? We can check pretty easy by passing a second parameter to the verify method like so:
The above code will verify that our method was not just called, but only called once. Pretty kewl right? But wait! There’s more! Let’s check out a bunch of different counter scenarios below.
How to verify a method was called at least x times:
Wow wow wow, so many options for so many scenarios, however I would be remiss if I didn’t also should you the description method call you can chain to basically give you useful verification failure statements. Let’s check that out right quick:
((fflib_ISObjectUnitOfWork)mocks.verify(mockUOW, mocks.times(2).description('Whoa champ, you didnt call this dirty method twice, try again broseph'))).registerDirty(caseMatchingList);
If your verification fails (and in turn your test class fails) you will now get that wonderful description to help you pinpoint the cause of your test failure a bit easier. That’s pretty awesome opposum.
If we couldn’t produce fake records to pass to our mocked class methods to handle, honestly this whole setup would only be kinda good because we’d always be forced to do real DML transactions in our tests to create data, and if you didn’t know the reason tests can take sooooooooooooo long is because of DML transactions. They take a crazy amount of time in comparison to everything else in your code (unless you’ve got quadruple inner for loops in your codebase somewhere… which you should address like right now, please stop reading this and fix it). So let’s figure out how to make fake data using the Apex Mocks Library.
The first class on our list in the Apex Mocks library to check out is the fflib_IDGenerator class. Inside this class there is a single method, generate(Schema.SObjectType sobjectType) and its purpose is to take an SObjectType and return an appropriate Id for it. This is super useful because if you need to fake that a record already exists in the system, or that a record is parented to another record, you need an Id. You’ll likely use this method a ton.
Example method call to get a fake (but legal) Id:
Id mockCaseId = fflib_IDGenerator.generate(Case.SObjectType);
That will return to you a legal caseId! Pretty useful.
The next class on our list to cover here is the fflib_ApexMocksUtils class. This class has three accessible methods and they allow you to make in memory relationships between fake records and to setup formula field values for a fake record. Let’s take a look at some examples below.
//Example from: https://salesforce.stackexchange.com/questions/315832/mocking-related-objects-using-fflib
Opportunity opportunityMock1 = new Opportunity(Id = fflib_IDGenerator.generate(Opportunity.SObjectType));
//This basically creates a list of opportunities with child opportunity line items in the list in the OpportunityLineItems field
List<Opportunity> opportunitiesWithProductsMock = (List<Opportunity>) fflib_ApexMocksUtils.makeRelationship(
List<Opportunity>.class,
new List<Opportunity>{
opportunityMock1
},
OpportunityLineItem.OpportunityId,
new List<List<OpportunityLineItem>>{
new List<OpportunityLineItem>{
new OpportunityLineItem(Id = fflib_IDGenerator.generate(OpportunityLineItem.SObjectType)),
new OpportunityLineItem(Id = fflib_IDGenerator.generate(OpportunityLineItem.SObjectType))
}
}
);
//This is basically the same method as above, but you can pass in String to determine the object and relationship instead of types. I would
//use the method above unless this one was 110% necessary.
List<Opportunity> opportunitiesWithProductsMock = (List<Opportunity>) fflib_ApexMocksUtils.makeRelationship(
'Opportunity',
'OpportunityLineItem',
new List<Opportunity>{
opportunityMock1
},
'OpportunityId',
new List<List<OpportunityLineItem>>{
new List<OpportunityLineItem>{
new OpportunityLineItem(Id = fflib_IDGenerator.generate(OpportunityLineItem.SObjectType)),
new OpportunityLineItem(Id = fflib_IDGenerator.generate(OpportunityLineItem.SObjectType))
}
}
);
//Code from: https://github.com/apex-enterprise-patterns/fflib-apex-mocks
Account acc = new Account();
Integer mockFormulaResult = 10;
//This will allow you to set read only fields on your objects, such as the formula field below. Pretty useful!
acc = (Account)fflib_ApexMocksUtils.setReadOnlyFields(
acc,
Account.class,
new Map<SObjectField, Object> {Account.Your_Formula_Field__c => mockFormulaResult}
);
Example Apex Mocks Classes
Task_Service_Impl_Test – Apex Mocks test class example that uses the Apex Common library.
Next Section
That’s it! You’re done! Thank god… I’m tired of writing this thing. You can go back to the home page here.