Automated testing of D365FO SSRS Reports with simple Page Object Model

There are various strategies for testing the content of reports using automation. In this article we look at how we can render an SSRS report in memory and then query an XML representation of its content using X++.

If we develop a new or extend an existing SSRS report, it’s a good idea to add some further tests to our delivery pipeline to make sure it behaves as the user expects and to automatically pick up on any future regressions.

We could test the data set returned by the underlying report query, or by inspecting the contents of our temporary tables that supply data to the report, however this approach won’t necessarily pick-up on any defects introduced into the report design itself (encoding business logic into the report is not the best approach, but there are times when it is the only pragmatic approach.)

A different approach therefore is to test the content of the report once it has been rendered by SQL Server Reporting Services (SSRS) and converted into an XML format (it’s also possible to render to HTML, but that approach isn’t for the faint of heart!)

Thankfully, Merit solutions posted some code to take the hard work out of rendering the report in memory. We can use that class as the basis for a simple abstract Page Object Model of the report:

public void run()
//Configure the SrsReportRunController controller
//Associate the Rdp contract with prepopulated values if we have one
//Configure print settings to render the output to XML
SRSPrintDestinationSettings settings = controller.parmReportContract().parmPrintSettings();
//Bootstrap the SRSReportRunService
//Marshall the parameters from the contract
Map reportParametersMap = srsReportRunService.createParamMapFromContract(controller.parmReportContract());
Microsoft.Dynamics.AX.Framework.Reporting.Shared.ReportingService.ParameterValue[] parameterValueArray =
//Render the report to a byte array
SRSProxy srsProxy = SRSProxy::constructWithConfiguration(controller.parmReportContract().parmReportServerConfig());
System.Byte[] reportBytes = srsproxy.renderReportToByteArray(controller.parmreportcontract().parmreportpath(),
if (reportBytes)
//Create an XMLDocument from the byte array
System.IO.MemoryStream stream = new System.IO.MemoryStream(reportBytes);
xmlDocument = XmlDocument::newFromStream(stream);
throw Exception::Error;

The report page model is held in memory by an XmlDocument object. For each report that we want to test, we can add further concrete pages with report implementation specific details:

public class wwSysUserRoleInfoReportPage extends wwBaseReportPage
protected void new()
this.parmReportName(ssrsReportStr(SysUserRoleInfo, Report));
public static wwSysUserRoleInfoReportPage construct()
return new wwSysUserRoleInfoReportPage();
public void run()
//Add any further required clean-up tasks here.. e.g.
// classStr(SalesInvoiceDP), executionInfo);
//Encapsulate the element names here so the test doesn't
//need to know about the implementation. This will improve
//maintenance if the design changes
public int roleCount()
return this.elementCount('RoleName_0');
public boolean isRoleIncluded(str role)
return this.elementExists('RoleName_0', 'userID1', role);
view raw reportPageModel.xpp hosted with ❤ by GitHub

And our tests can ask the pages about the values rendered in the reports without knowing about the underlying implementation details (hopefully making the tests less brittle.)

public class wwReportExampleTest extends SysTestCase
public void TestReport()
wwSysUserRoleInfoReportPage report =
//Pass arguments here if the report has a contract
//and vary according to the test
//SysUserLicenseCountRDPContract contract = new
//Let's make sure the report lists out all 33
//(or however many) expected users
this.assertEquals(33, report.roleCount());
//Let's make sure the HR assistant appears on the
//report as expected
report.isRoleIncluded('Human resource assistant'));

You can read more about test automation using the Page Object Model in this article.

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

Create a website or blog at

Up ↑

%d bloggers like this: