Wednesday, 1 August 2012

Parsing MSTEST results (.trx files) programmatically (in C#)

 

Hello, it’s been quite awhile since I’ve posted anything; I’ve been quite busy.  I just felt like sharing this.  This is an extension of other people’s ideas, but I’ve taken it slightly further and thought it might be useful to somebody.

I came across a situation where I needed to programmatically examine a .trx file for specific strings.  The .trx file was large (31MB) because it contained the output of around 5000 unit tests.  Around 800 of those tests were failed tests, and they were failing for a specific reason (which is not important now).  The point is, I wanted to programmatically examine the error messages that were being output, and do something (which is also not important now), based on certain strings that might be found in the error message of each failed test.

Searching led me to this post in Rasheed’s blog, which was a great starting point for what I wanted to do.  As described in that post, first I had to:

Use XSD.EXE (see MSDN here) to generate classes based on the schema of VSTST.XSD. 

(XSD.EXE can be found in the Windows SDK).

(If you’re running Visual Studio 2010, then VSTST.XSD can be found in the Xml\Schemas directory on your local drive; in my case that was):

C:\Program Files (x86)\Microsoft Visual Studio 10.0\Xml\Schemas

So I copied VSTST.XSD to a working directory on my C:\ drive, let’s call it C:\Projects\VSTST-CLASSES.

Then I executed this command:

C:\Projects\VSTST-CLASSES>"C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Bin\NETFX 4.0 Tools\xsd.exe" vstst.xsd /c

That generated a file called VSTST.CS.  In Visual Studio, in a new console application, I chose “Add Existing Item” and added that .CS file to the project to give me access to the generated classes.

Then (as described in the user comments in Rasheed’s blog ), I had to go into VSTST.CS, which now contains a load of classes that can be used to deserialize your test data, and comment out the “Items” properties of the GenericTestType and CodedWebTestElementType, to get the test results data to deserialize without error.

The end result of all this can be seen in the following C# code (which is a variation of Rasheed’s, but, I don’t care about outputting it to Excel; I’m just trying to find certain strings in the error message, probably so I can output that text to a separate output file, which will probably be a text file in any case).  Modify as desired to find the string you want in the error message of your failed test.  This code deserializes your test results and lets you loop through them and do something  based on the contents of the error message on failed unit tests.

using System.IO;

using System.Xml;

using System.Xml.Serialization;

 

namespace Utility

{

 

    class Program

    {

        static void Main(string[] args)

        {

            var fileInfo = new FileInfo(@"C:\thePathToMyGiganticTrxFile\DBarrows@R9D0YGF 2012-07-16 20_08_01.trx");

 

            var fileStreamReader = new StreamReader(fileInfo.FullName);

 

            var xmlSer = new XmlSerializer(typeof(TestRunType));

            var testRunType = (TestRunType)xmlSer.Deserialize(fileStreamReader);

 

            foreach (var itob1 in testRunType.Items)

            {

                var resultsType = itob1 as ResultsType;

                if (resultsType == null) continue;

 

                foreach (var itob2 in resultsType.Items)

                {

                    var unitTestResultType = itob2 as UnitTestResultType;

 

                    if (unitTestResultType == null) continue;

 

                    // these are not used, but they could be to identify the output:

 

                    // var id = unitTestResultType.testId;

                    // var testName = unitTestResultType.testName;

 

                    var outcome = unitTestResultType.outcome;

 

                    if (outcome != "Failed") continue;

 

                    var items = unitTestResultType.Items;

 

                    if (items == null || items.Length <= 0) continue;

 

                    // now we know we have a failed test; look for the desired string(s) in the error message

                    var outputType = (OutputType) unitTestResultType.Items[0];

                    var errorInfo = outputType.ErrorInfo;

                    var message = errorInfo.Message;

                    var text = ((XmlNode[]) message)[0].InnerText;

 

                    if (text.ToLower().Contains("some_pertinent_string"))

                    {

                        // do something special if the error message contains some particular string,

                        // e.g. parse the error message further and output as desired

                    }

                }

            }

        }

    }

}