Simon Harriyott

Running MSTest from MSBuild

A while ago I wrote about running mstest.exe from MSBuild. I gave details of the MSBuild script, but not the utility to rewrite the file paths. Arundhati emailed me for some more details, so instead of emailing him the details, I thought I'd blog them.

The first step is to add a list of tests in Visual Studio, and move the tests into this list. Most of the source is here, but some of the simpler methods (like reading and writing the files) I'll leave out for brevity.

// Call this from Main, passing the args

public int ReplaceAbsolutePath(string[] args)


    // Ensure that an argument has been passed in, and the file exists

    if (IsArgumentValid(args) == false)

        return 1;


    // Load the file

    if (LoadTestConfigData() == false)

        return 1;


    // Replace the XML with the file's path

    if (ReplaceDirectoryName() == false)

        return 1;


    // Write the XML back to disk

    if (WriteXmlToFile() == false)

        return 1;


    // Success!

    return 0;


Choose the replacement method:

private const string testRunConfigExtension = ".testrunconfig";

private const string vsmdiExtension = ".vsmdi";


private bool ReplaceDirectoryName()


    // Compare the extension to see which time of replacement to do.

    FileInfo testConfigFile = new FileInfo(testConfigFileName);

    string extension = testConfigFile.Extension;


    // Depending on the file type, do the replacement

    if (extension == testRunConfigExtension)

        return ReplaceDirectoryForTestRunConfig();

    if (extension == vsmdiExtension)

        return ReplaceDirectoriesForVsmdi();


    // Should have returned by now.

    Console.WriteLine("Couldn't replace directory name");

    return false;


.vsmdi replacement:

private const string xpathLocalTestRunStorage = "/Tests/TestCategory/runConfiguration/storage";

private const string xpathAssemblyStorage = "/Tests/TestCategory/testLinks/value/storage";

private const string localTestRunFileName = @".\localtestrun.testconfig";


private bool ReplaceDirectoriesForVsmdi()


    // Replace the localtestrun.testrunconfig storage value with

    // a relative path.

    ReplaceNodeInnerText(xpathLocalTestRunStorage, localTestRunFileName);


    // Find all storage nodes in the XML

    XmlNodeList storageNodes = testConfigData.SelectNodes(xpathAssemblyStorage);

    // Loop through them, and set the correct absolute path.

    foreach (XmlNode storageNode in storageNodes)


        if (GetDirectoryForVsmdi(storageNode) == false)


            return false;




    return true;



private bool GetDirectoryForVsmdi(XmlNode node)




        // Get the directory currently used from the vsmdi file

        string currentAssembly = node.InnerText;


        string inputDirectory = GetInputDirectoryName().ToLower();


        // Find the lowest level directory of the vsmdi file location.

        string[] allDirectories = inputDirectory.Split('\\');

        string lowestDirectory = allDirectories[allDirectories.Length - 1];


        // Find this directory in the current setting, and note the position of the

        // end of the string.

        int stringPosition = currentAssembly.IndexOf(lowestDirectory) + lowestDirectory.Length;


        // Remove everything above (and including) this directory in the vsmdi directory name.

        currentAssembly = currentAssembly.Substring(stringPosition);


        // Add the current path root to the remainder of the assembly path.

        currentAssembly = inputDirectory + currentAssembly;


        // Replace the current node text with the new directory.

        node.InnerText = currentAssembly;


    catch (Exception e)




        return false;


    return true;


Replace the xml

private const string xpathRelativePathRoot = "/Tests/TestRunConfiguration/relativePathRoot";


private bool ReplaceDirectoryForTestRunConfig()


    return ReplaceNodeInnerText(xpathRelativePathRoot, GetInputDirectoryName());



private bool ReplaceNodeInnerText(string xpath, string newText)


    // Navigate to the relative path root node in the data file.

    XmlNode node = testConfigData.SelectSingleNode(xpath);

    if (node == null)

        Console.WriteLine("Couldn't find node: " + xpath);


        // Replace the existing path with the new one.

        node.InnerText = newText;

    return true;



private string GetInputDirectoryName()


    // Get the directory from the XML filename.

    FileInfo testConfigFile = new FileInfo(testConfigFileName);

    string directoryName = testConfigFile.DirectoryName;

    return directoryName;


Hopefully this is enough to get you started.

[Tags: ]
18 August 2006