apex-enterprise-patterns / fflib-apex-mocks

An Apex mocking framework for true unit testing in Salesforce, with Stub API support
BSD 3-Clause "New" or "Revised" License
423 stars 214 forks source link

Multiple selector mocks #56

Closed wimvelzeboer closed 6 years ago

wimvelzeboer commented 7 years ago

How do you use multiple selector mocks with ffib ApexMock? In the example below, they use only one selector mock: IOpportunitiesSelector selectorMock = new Mocks.OpportunitiesSelector(mocks); But how should it look like if the applyDiscounts method used two selectors to query its data, like Opportunites and Accounts (selectById)?

Any thoughts?

@IsTest
private static void callingServiceShouldCallSelectorApplyDiscountInDomainAndCommit()
{
    // Create mocks
    fflib_ApexMocks mocks = new fflib_ApexMocks();
    fflib_ISObjectUnitOfWork uowMock = new fflib_SObjectMocks.SObjectUnitOfWork(mocks);
    IOpportunities domainMock = new Mocks.Opportunities(mocks);
    IOpportunitiesSelector selectorMock = new Mocks.OpportunitiesSelector(mocks);

    // Given
    mocks.startStubbing();
    List<Opportunity> testOppsList = new List<Opportunity> { 
        new Opportunity(
            Id = fflib_IDGenerator.generate(Opportunity.SObjectType),
            Name = 'Test Opportunity',
            StageName = 'Open',
            Amount = 1000,
            CloseDate = System.today()) };
    Set<Id> testOppsSet = new Map<Id, Opportunity>(testOppsList).keySet();
    mocks.when(domainMock.sObjectType()).thenReturn(Opportunity.SObjectType);
    mocks.when(selectorMock.sObjectType()).thenReturn(Opportunity.SObjectType);
    mocks.when(selectorMock.selectByIdWithProducts(testOppsSet)).thenReturn(testOppsList);
    mocks.stopStubbing();
    Decimal discountPercent = 10;
    Application.UnitOfWork.setMock(uowMock);
    Application.Domain.setMock(domainMock);
    Application.Selector.setMock(selectorMock);

    // When
    OpportunitiesService.applyDiscounts(testOppsSet, discountPercent);

    // Then
    ((IOpportunitiesSelector) 
        mocks.verify(selectorMock)).selectByIdWithProducts(testOppsSet);
    ((IOpportunities) 
        mocks.verify(domainMock)).applyDiscount(discountPercent, uowMock);
    ((fflib_ISObjectUnitOfWork) 
        mocks.verify(uowMock, 1)).commitWork();
}
XoNoXForce commented 7 years ago

If I'm understanding correctly your question, you are going to have something like:

//mock creation IAccountsSelector accSelectorMock = new Mocks.AccountsSelector(mocks); //stubbing mocks.when(accSelectorMock.sObjectType()).thenReturn(Account.SObjectType); mocks.when(accSelectorMock.selectById(testAccsSet)).thenReturn(testAccsList); ` //injection the mock Application.Selector.setMock(accSelectorMock); //verify ((IAccountsSelector) mocks.verify(accSelectorMock)).selectById(testAccsList);`

the Application would match the mocks on the base of the Interface type

dfruddffdc commented 6 years ago

Like Vincenzo says, follow the same pattern to add more selectors. So everywhere you create, stub, verify etc your OpportunitiesSelector, add an equivalent for the AccountsSelector.


// Instantiate both mock selectors
IOpportunitiesSelector opportunitiesSelectorMock = new Mocks.OpportunitiesSelector(mocks);
IAccountsSelector accountsSelectorMock = new Mocks.AccountsSelector(mocks);

// Stub both SObjectType() methods
mocks.when(opportunitiesSelectorMock.sObjectType()).thenReturn(Opportunity.SObjectType);
mocks.when(accountsSelectorMock.sObjectType()).thenReturn(Account.SObjectType);

// Stub your select methods
mocks.when(opportunitiesSelectorMock.selectByIdWithProducts(testOppsSet)).thenReturn(testOppsList);
mocks.when(accountsSelectorMock.selectSObjectsById(testAccountsSet)).thenReturn(testAccountsList);

// Register both mock selectors in the Application factory
Application.Selector.setMock(opportunitiesSelectorMock);
Application.Selector.setMock(accountsSelectorMock);

// Verify both mocks were invoked as expected
((IOpportunitiesSelector)mocks.verify(opportunitiesSelectorMock)).selectByIdWithProducts(testOppsSet);
((IAccountsSelector)mocks.verify(accountsSelectorMock)).selectSObjectsById(testAccountsSet);