EDIT - I had some trouble deserializing the JSON due to nulls etc.
To get around this, you can remove the factMap and make sure that other data types are correct like so:
String jsonReport = '{"hasDetailRows":true,"groupingsDown":{"groupings":[]},"groupingsAcross":{"groupings":[]},"allData":true, "reportMetadata":{"topRows":{},"standardFilters":[],"standardDateFilter":{"startDate":null,"endDate":null,"durationValue":"CUSTOM","column":"CREATED_DATE"},"sortBy":[],"showSubtotals":true,"showGrandTotal":true,"scope":"user","reportType":{"type":"AccountList","label":"Accounts"},"reportFormat":"TABULAR","reportFilters":[],"reportBooleanFilter":"","name":"Dummy","id":"00O3B000000Jl8xUAC","historicalSnapshotDates":[],"hasRecordCount":true,"hasDetailRows":true,"groupingsDown":[],"groupingsAcross":[],"division":"","developerName":"Dummy","detailColumns":["TYPE"],"description":"","customSummaryFormula":{},"currencyCode":"USD","crossFilters":[],"buckets":[],"aggregates":["RowCount"]}}';
Reports.ReportResults results = (Reports.ReportResults)JSON.deserialize(jsonReport, Reports.ReportResults.class);
Then deserialize the factMap separately:
String reportFacts = '{"T!T":{"key":"T!T","aggregates":[{"value":4,"label":"4"}],"rows":[{"dataCells":[{"value":"test1","label":"test1"}]},{"dataCells":[{"value":"test2","label":"test2"}]},{"dataCells":[{"value":"test3","label":"test3"}]},{"dataCells":[{"value":"test4","label":"test4"}]}]}}';
Reports.ReportFactWithDetails factMapWithDetails = (Reports.ReportFactWithDetails)JSON.deserialize(reportMetaExtend, Reports.ReportFactWithDetails.class);
At this point, you can't get the factmap back into the main report object, so perhaps the best way to deal with this is to use the separate pieces (metadata, extendedMetadata, factmap) separately, both in Testing and general usage.
If anyone has any luck deserializing the entire report object, please post your results as a comment here.
I just ran into this annoying issue - however, I think there is a better way.
Instead of having an actual report having to be around and having SeeAllData=True
,
Use JSON deserialization to help!
In your test class, define a string containing the report that you want to generate (ie your mock), and then just deserialize it like so:
//define JSON
private static String dummyReportString = '{"reportMetadata":{"topRows":null,"standardFilters":null,"standardDateFilter":{"startDate":"2016-10-30","endDate":null,"durationValue":"CUSTOM","column":"CREATED_DATE"},"sortBy":null,"showSubtotals":true,"showGrandTotal":true,"scope":"user","reportType":{"type":"AccountList","label":"Accounts"},"reportFormat":"TABULAR","reportFilters":null,"reportBooleanFilter":null,"name":"Dummy","id":"00O3B000000Jl8xZOO","historicalSnapshotDates":null,"hasRecordCount":true,"hasDetailRows":true,"groupingsDown":null,"groupingsAcross":null,"division":null,"developerName":"Dummy","detailColumns":["USERS.NAME"],"description":null,"customSummaryFormula":null,"currencyCode":null,"crossFilters":null,"buckets":null,"aggregates":["RowCount"]},"reportExtendedMetadata":{"groupingColumnInfo":null,"detailColumnInfo":{"USERS.NAME":{"name":"USERS.NAME","label":"Account Owner","dataType":"STRING_DATA"}},"aggregateColumnInfo":{"RowCount":{"name":"RowCount","label":"Record Count","downGroupingContext":null,"dataType":"INT_DATA","acrossGroupingContext":null}}},"hasDetailRows":true,"groupingsDown":{"groupings":null},"groupingsAcross":{"groupings":null},"factMap":{"T!T":{"key":"T!T","aggregates":[{"value":4,"label":"4"}],"rows":[{"dataCells":[{"value":"005i00000080XvdAHC","label":"Some Dude"}]},{"dataCells":[{"value":"005i00000080XvdAUO","label":"Some Dude"}]},{"dataCells":[{"value":"005i00000080XvdAGC","label":"Some Dude"}]},{"dataCells":[{"value":"005i00000080XvdAEK","label":"Some Dude"}]}]}},"allData":true}';
//deserialize:
Reports.ReportResults results = (Reports.ReportResults)JSON.deserialize(dummyReportString, Reports.ReportResults.class);
Then just use as a normal report. I have used mine in the report retrieval class so that when called, it always returns a report (a normal one in normal circumstances or if Test.isTest() == true
- the fake one.
SeeAllData
anyway, you could use aCustom Setting
to manage whichReport(s)
to use.