Param is unnamed__0 if StubProvider used on interface (instead class)
This is subtle...
If I write an object to implement the ShopBackend
interface, there's no requirement that this object chooses the same parameter names as the interface. It only has to match the signature in terms of types and order.
So, I can quite happily write
public class ShopFoo implements ShopBackend {
public void initialize() {
}
public Boolean hasInStock(String foo) {
return true;
}
}
I've implemented ShopBackend
correctly, but I've changed the parameter name of hasInStock
from item
to foo
.
If you were to test that against mock which expects the parameter names to be the same, it would fail. But, in reality, that is a valid way of implementing the interface.
Why does it work with fflib-apex-mocks as per @stohn's answer? Because the fflib version is constructing the expectation of which methods are going to be called by recording what it hears via the Stub API. So, when you write
mocks.startStubbing();
mocks.when( mockedBackend.hasInStock(itemToBeTested) ).thenReturn(true);
mocks.stopStubbing();
fflib-apex-mocks is using the Stub API to make the list of what methods to expect. This means that if the Stub API turn the names into unnamed__0
, it does it both on the expectation and the actual test execution. So, everything matches.
So, it could be better explained in the docs, but I think what you're attempting to do here is actually being too specific in your verification. You should only expect that the method names, and parameter types + order is correct. Expecting the parameter names is unnecessary and can lead to false failures.
With the installation of fflib-apex-mocks [1], a slightly different implementation of the Shop
code, and using the included test class implementing fflib-apex-mocks, the interface could be successfully mocked.
Something could be amiss with the mocking implementation of your usage.
public inherited sharing class Shop
{
private IShopBackend backend = null;
private String shoppingResult = null;
public Shop(IShopBackend backend)
{
this.backend = backend;
}
public void buy(String item_name)
{
backend.initialize();
if (backend.hasInStock(item_name))
shoppingResult = 'Item in stock';
else {
shoppingResult = 'Item IS NOT in stock';
}
}
//=================================
// Testing functionality
//=================================
@TestVisible
private String getResultStatus()
{
return shoppingResult;
}
}
@IsTest
public class ShopTest
{
@IsTest
private static void test()
{
String itemToBeTested = 'FizzBuzz';
// FFLIB mock implementation
fflib_ApexMocks mocks = new fflib_ApexMocks();
IShopBackend mockedBackend = (IShopBackend) mocks.mock(IShopBackend.class);
mocks.startStubbing();
mocks.when( mockedBackend.hasInStock(itemToBeTested) ).thenReturn(true);
mocks.stopStubbing();
// Exercise the target
Shop s = new Shop(mockedBackend);
s.buy(itemToBeTested);
// Verify the results
((IShopBackend) mocks.verify(mockedBackend)).initialize();
((IShopBackend) mocks.verify(mockedBackend)).hasInStock(itemToBeTested);
System.assertEquals('Item in stock', s.getResultStatus());
}
}
[1] https://github.com/apex-enterprise-patterns/fflib-apex-mocks