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

How to use matcher to see if set contains or map containsKey or map (for key) has value? #51

Closed cropredyHelix closed 6 years ago

cropredyHelix commented 7 years ago

Looking through the examples in fflib_Match.cls and fflib_ApexMocksTest.cls I'm not seeing any way to

My example is testing a VF controller that calls a FooService.doBar(..) Hence, mocking a service FooServiceImpl, method doBar(map<ID,Foo.CustomType>)

I tried this (match on entire map)

// preamble to set up mocks and inject not shown ; it works fine
((FooServiceImpl) mocks.verify(mockFooSvc,1))
  .doBar(new map<ID,Foo.CustomType> {someId => new Foo.CustomType(arg1, arg2)});

but even though doBar is called with the map someId => new Foo.CustomType(arg1, arg2) (verified using debug), the verify method in ApexMocks comes back with

Expected : 1, Actual: 0 -- Wanted but not invoked: FooServiceImpl__sfdc_ApexStub.doBar(Map<Id,Foo.CustomType>)

So, bottom line - would be nice to see how to use matchers on sets (specific entry) and maps (entire map, hasKey, hasValueForKey, etc.) - especially without having to resort to custom matchers.

cropredyHelix commented 7 years ago

After some inspired searching on frup42 blog, I now see how to use fflib_ArgumentCaptor to solve the above on verifying maps. Still seems as if there should be enhancement possibilities for more matchers on fflib_Match to deal with sets.

dfruddffdc commented 6 years ago

Another Apex quirk... This compiles fine:

List<Account> records = new List<Account>{};
List<Object> castUp = (List<Object>)records;
List<Account> castDown = (List<Account>)castUp;

But this doesn't compile, because: Incompatible types since an instance of Set is never an instance of Set

Set<Account> records = new Set<Account>{};
Set<Object> castUp = (Set<Object>)records;
Set<Account> castDown = (Set<Account>)castUp;

Likewise with Maps. So we can't write generic matchers for Maps and Sets, we have to have a specific matcher for the specific Typed Maps/Sets. This would be a lot of matchers, but not particularly useful for the majority of ApexMocks consumers.

So when the requirement comes up, we just let the consumer use captors or custom matchers knowing the specific Types in question in their test.