I so much wanted @AdrianLarson original Json.deserialize answer to be right as it is easy to fabricate but while it works at compile time, at run time, the deserialized AggregateResult
is empty ( debug displays as {}
).
So, here's what I did:
Create an AggregateResultProxy object
/**
* AggregateResult can't be mocked so wrap with AggregateResultProxy
* which can be mocked by test methods.
*/
public class AggregateResultProxy {
Map<String,Object> valuesByAlias = new Map<String,Object> ();
public AggregateResultProxy withAggregateResult(AggregateResult groupedResult) {
String groupedResultJson = JSON.serialize(groupedResult);
this.valuesByAlias = (Map<String,Object>) JSON.deserializeUntyped(groupedResultJson);
return this;
}
public AggregateResultProxy withAliasAndValue(String alias, Object val) {
this.valuesByAlias.put(alias,val);
return this;
}
public Map<String,Object> getValuesByAlias() {return this.valuesByAlias;}
}
My selector method
return not a List<AggregateResult>
but instead a List<AggregateResultProxy>
AggregateResultProxy[] mySelectorMethod(...) {
AggregateResultProxy[] groupedResultProxies = new List<AggregateResultProxy>();
for (AggregateResult groupedResult:
[SELECT COUNT(ID) RECORDCOUNT, Status STATUS
FROM Asset
WHERE ...
GROUP BY Status ] ) {
groupedResultProxies.add(
new AggregateResultProxy().withAggregateResult(groupedResult));
}
return groupedResultProxies;
}
My runtime code
public void doStuff() {
for (AggregateResultProxy groupedResultProxies :AssetsSelector.newInstance().mySelectorMethod() ) {
Map<String,Object> groupedResultProxy = groupedResultProxies.getValuesByAlias();
System.debug('Status = ' + groupedResultProxy.get('STATUS'));
System.debug('Count = ' + groupedResultProxy.get('RECORDCOUNT'));
}
}
which might display
Status = Active
Count = 23
Status = Canceled
Count = 6
and my testmethod
using ApexMocks (you could of course use your own favorite dependency injection approach)
fflib_ApexMocks mocks = new fflib_ApexMocks();
// given mocked AggregateResults
AggregateResultProxy[] mockedGroupedResults = new List<AggregateResultProxy> {
new AggregateResultProxy()
.withAliasAndValue('STATUS','Active')
.withAliasAndValue('RECORDCOUNT', 2),
new AggregateResultProxy()
.withAliasAndValue('STATUS','Cancelled')
.withAliasAndValue('RECORDCOUNT', 7)
};
// Given mock selector (stubbed return val)
AssetsSelector mocksSelector = (AssetsSelector) mocks.mock(AssetsSelector.class);
mocks.startStubbing();
mocks.when(mocksSelector.sObjectType()).thenReturn(Asset.SObjectType);
mocks.when(mocksSelector.mySelector(...))
.thenReturn(mockedGroupedResults);
mocks.stopStubbing();
// Given mocks injected
Application.Selector.setMock(mocksSelector);
// When myMethodUnderTestIsCalled
myObject.doStuff();
// Then verify ...
...asserts or apexMocks verifies go here