Wednesday, July 6, 2011

Generic Unit Tests for Dynamics AX in Visual Studio

A little while ago, I blogged about unit testing and integrating this with TFS builds. We have this running currently, but with some drawbacks. We basically wrap each X++ unit test method in a test method in C#, which reads the AX unit test XML results file and either throws an error or passes the test. As Dave Froslie pointed out to me, there is such a thing as "generic tests" in Visual Studio. This is basically a means to invoke an external process, which can then generate a summary results file in .TRX (xml) format.
That of course would be a much more efficient way of doing this. Seeing that AX has "listener" classes, which can subscribe to the unit test framework's output, all we need to do is create one that writes the TRX format that Visual Studio is expecting…

I have created the listener and it's up for download on the AX Build project on CodePlex. In this post I will describe how to set up the generic test in Visual Studio 2010. This process works for both AX 2009 and AX 2012. The code is the same, but make sure you download the right XPO from CodePlex (AX 2009 doesn't like the AX 2012 XPO format).

For a quick overview on how to create unit tests in AX, please check out the following pages on MSDN for AX2009 and AX2012.

For the purpose of this walkthrough, we'll assume you have an X++ test project containing your tests (aka "test suite"). Let's also assume this project is called "TFSGenericTestProject". Replace with the name of your actual unit test project in AX.

First, download the SysTestListenerTRX class for AX2009 or AX2012 from the AX Build CodePlex project. Import the class into AX. This implements the TRX format for a unit test "listener". A listener is a class AX unit tests use to output their results. TRX is the result file format which generic unit tests in Visual Studio can read. Feel free to open these, they're basically XML files. To make the generic unit tests work, all you need is the class. The enum you'll need if you want to run the TRX listener when running unit tests inside AX, but is not necessary for the TRX listener to work.

AX unit tests can be run from a command line. You can start the AX client as usual (either using the default config in the registry, or by passing a config file as the first command line argument. Furthermore, you can pass "RunTestProject" as a startup command, followed by an underscore, followed by the name of the AX unit test project. The syntax for this is a little strange perhaps:


Where "TFSGenericTestProject" is the name of your test project in AX. Now, the parsing of these arguments get even more interesting. The class that runs the unit test project supports two more arguments; one that supplies the name of the listener, and any subsequent arguments will be passed into the NEW method of your listener (the TRX listener's NEW method accepts an optional filename). The listeners are all called SysTestListener_NAME, and it's that "name" you need to pass as an argument. So, putting this all together, to start AX using a configfile.axc, run our TFSGenericTestProject with the TRX listener, and output the file to c:\unittest.trx, you would use the following command line:

Ax32.exe "configfile.axc" -StartupCmd=RunTestProject_TFSGenericTestProject@TRX@C:\unittest.trx

Now, if your filename/path contains spaces, you will need to wrap the whole thing in quotes. Since the -StartupCmd and the consequent class names etc are considered 1 argument, you would have to wrap it from start to end, as such:

Ax32.exe "configfile.axc" "-StartupCmd=RunTestProject_TFSGenericTestProject@TRX@C:\my folder with spaces\unittest.trx"

Ok, so now we're ready to create our Visual Studio generic test project. If you already have a solution (.sln) for your TFS project (which you will if you're using builds), you will add a new project to the existing solution, don't start a new solution. For the new project, select the Test template / Test Project. This will actually create a new test class for you, but we do not want to use this, so go ahead and delete that UnitTest1.cs file. Right-click your project again, and select Add / Generic Test.

As the existing program we wish to wrap, enter the path to your AX client (Ax32.exe). The command-line arguments are the arguments we talked about earlier, except one difference. The generic test supplies a variable for the test output directory, which we can leverage for our summary results TRX file. The only thing we want to change is the result settings, where we can specify the filename/path of the TRX file. Also note there is a time-out feature (this can be useful in case your ax client can't connect to the AOS).

Once you have this setup, you're DONE! Assuming you actually have an AX unit test project called "TFSGenericTestProject", you can now run this test, and you will see it open AX, run the tests, close AX, and Visual Studio will show you the results of your tests. Double-click on the test results at the bottom to see a break-down of your methods, with their results and the messages associated with them.

The test project should be automatically included in your TFS builds if you're using that, assuming you added the test project to the build solution, and it contains "test" in its name. In your build definition under "Process" you will find a section under Basic that runs the tests based on names containing *test*.

No comments:

Post a Comment