Trying to test a simple overloaded service.
AccountsService.cls
public static List<Account> getAccounts(Set<Id> ids){
/* This selector needs to be mocked */
List<Account> accounts = AccountsSelector.newInstance().selectById( ids );
if(accounts != null && accounts.size() > 0) {
return accounts;
} else {
return NULL;
}
}
public static List<Account> getAccounts(Set<String> ids){
return getAccounts( (Set<Id>)JSON.deserialize(JSON.serialize(ids), Set<Id>.class) );
}
My thought here is that I simply need to unit test the Set<String>
method which will reference the derived method, which then will call the AccountsSelector which should be stubbed per my test.
AccountsServiceTest.cls
@IsTest
private static void getAccounts() {
/* Create mocks */
fflib_ApexMocks MOCKS = new fflib_ApexMocks();
AccountsSelector mockSelector = (AccountsSelector) MOCKS.mock(AccountsSelector.class);
/* Generate a generic account id */
Id aid = fflib_IDGenerator.generate(Account.SObjectType);
//! Given
MOCKS.startStubbing();
List<Account> accountsList = new List<Account> {
new Account(
Id = aid,
Name = 'Test Account'
)
};
MOCKS.when(mockSelector.selectById(aid)).thenReturn(accountsList);
MOCKS.stopStubbing();
/* Configure the application to use mocks */
Application.Selector.setMock(mockSelector);
//! When
AccountsService.getAccounts(new Set<Id>{aid});
//! Then
/* Verify services were called */
((AccountsSelector) MOCKS.verify(mockSelector)).newInstance().selectById(aid);
}
Unfortunately the test fails with the following response:
fflib_ApexMocks.ApexMocksException: Expected : 1, Actual: 0 -- Wanted but not invoked: AccountsSelector__sfdc_ApexStub.selectById(Id).
It seems the verify method is failing but I don't understand why, I feel like I'm missing something simple but after hours I'm not seeing it. I attempted to test against the method directly as well to make sure there wasn't an issue with the mocking and overloaded methods. I've also replaced the AccountsSelector
with the interface IAccountsSelector
but that doesn't seem to change anything either.
EDITED:
In addition when I remove the verify line the test passes without an issue and as you can see the AccountsSelector call was covered, so now I'm even more confused :/
Best Answer
This one is a common mistake; the fflib Selector layer requires that you stub the
SObjectType()
method as the setMock() method used byApplication.Selector.setMock(mockSelector)
callsSObjectType()
to properly instantiate an internal map of selector instances by SObjectTypes (so some selectors can be mocked and others not).I annotated your code below with the new line...
Now, some other things ...
You are testing
getAccounts
so you need to verify that it returns the accounts returned by the (mocked) selector. So, your verify is not what you wantYou have:
You need to verify the return from this method ...I altered your code below. There's no real need to verify that the selector was called because if the code under test doesn't pass in a set of mocked accountIds exactly the same as in your mocks.when, the selector will not return any Accounts and the code under test will not return any Accounts (will return NULL per the way you coded it)