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
417 stars 214 forks source link

Mock Generator: Invalid conversion from runtime type #31

Closed Xtremefaith closed 7 years ago

Xtremefaith commented 7 years ago

I finally got the 4.0.1 generator to work today (first crack at setting up ApexMocks. As expected the generated populated my Mocks.cls class.

Note: One thing to mention about this is I put ApexMocks into a managed package with a namespace because as a 3rd party tool I'd rather manage it like such. The generator ignores my package namespace so I have to manually add it to each property prior to deploying it

With that in place I'm attempting my first unit test with the following:

@IsTest
private class AccountsSelectorTest {

    @IsTest
    private static void selectById() {
        // Create mocks
        MyNamespace.fflib_ApexMocks mocks = new MyNamespace.fflib_ApexMocks();
        IAccountsSelector selectorMock = new Mocks.AccountsSelector(mocks);

        // Create our account but don't insert it into the database
        Account a = new Account(
            Id = MyNamespace.fflib_IDGenerator.generate(Account.SObjectType),
            Name = 'Test Account'
        );

        // Given
        mocks.startStubbing();
        // Use ApexMocks to stub the return value for the service's selectById() method
        mocks.when(selectorMock.selectById(new Set<Id> { a.Id })).thenReturn(a);
        mocks.stopStubbing();

        // When
        List<Account> accounts = selectorMock.selectById(new Set<Id> { a.Id });

        // Assert
        System.assertEquals('Test Account', accounts[0].Name);
    }

}

Unfortunately this test fails because of a fatal error coming from the generated mock class (Mocks.cls):

public class AccountsSelector extends SObjectMocks.SObjectSelector implements IAccountsSelector
{
    private AgasMocks.fflib_ApexMocks mocks;

    public AccountsSelector(AgasMocks.fflib_ApexMocks mocks)
    {
        super(mocks);
        this.mocks = mocks;
    }

    public List<Account> selectById(Set<ID> idSet)
    {
>>>ERROR>>> return (List<Account>) mocks.mockNonVoidMethod(this, 'selectById', new List<Type> {System.Type.forName('Set<ID>')}, new List<Object> {idSet});
    }
}

Sidebar: Is there a way to change the style guide used by the generator, would really like to see things like open brackets in their proper place ;)

19:29:11:023 FATAL_ERROR System.TypeException: Invalid conversion from runtime type Account to List

My Selector class method is setup just like the OpportunitiesSelector.cls example here.

Is this an issue because of the managed package? Or from what I can tell it has something to do with the fact that the fflib_ApexMocks.cls.mockNonVoidMethod() only expects an Object in return and can't handle a List<Object>?

Appreciate the help and the framework the more I'm understanding it all, so thank you!

afawcett commented 7 years ago

Once this is merged you will not need to use the generator. The Salesforce Apex Stub API takes care of this. So this will greatly simplify things for you.

The problem above is because you need to pass "a" as a List since the selectById method returns this. Hence your getting a class cast exception. So try passing a list of accounts to the thenReturn method when stubbing.

Also i assume you are testing your mock here just to demonstrate the issue? Normally you unit test something that is dependent on the selector, such as a service class. If you check out the apex commons repo readme file you can see some blogs and samples on this.

Hope this helps! 👍

dfruddffdc commented 7 years ago

Closing now that #28 is merged.