WCF服务方法创建一个Process来运行MsTest,该进程不会执行

WCF service method creates a Process to run MsTest, the process will not execute

我创建了一个 WCF 方法来执行 MsTest 命令来运行测试,例如:

Process process = new System.Diagnostics.Process();
ProcessStartInfo startInfo = new System.Diagnostics.ProcessStartInfo();
startInfo.FileName = @"cmd";
//I used Test Agent
startInfo.WorkingDirectory = @"C:\Program Files (x86)\Microsoft Visual Studio 12.0\Common7\IDE";
startInfo.UseShellExecute = false;
startInfo.RedirectStandardInput = true;
startInfo.CreateNoWindow = true;
process.StartInfo = startInfo;
process.Start();
process.StandardInput.WriteLine(@"mstest /testcontainer:MyTests.dll /test:MyTests.TestMethod1 /unique /resultsfile:C:\TestResults\TestMethod1.trx");

当我在控制台项目中调试此方法时,它运行良好。但是当我运行 WCF 测试方法时,似乎什么也没发生。我调试的时候可以调用WCF的方法,代码好像执行了,实际上没有结果。

请问您对此有什么想法吗?

下面修改后的代码将正确定位 mstest.exe 并验证输入和输出文件的存在。如果没有创建预期的输出,我们将抛出一个异常,并从过程中输出错误。我们只使用完整路径来避免更改工作目录。

这些更改至少应该为您指出从 WCF 使用它时出错的正确方向。

但是请注意,下面的代码存在多个错误,如果接受来自不受信任的客户端的输入,这些错误可能会影响安全性。警告程序员。

// Example use
RunTest(@"..\..\..\UnitTestProject1\bin\Debug\UnitTestProject1.dll", "UnitTest1.TestMethod2", "out2.trx");

private static void RunTest(string testDll, string testMethod, string outFile)
{
    //Contract.Requires(!String.IsNullOrEmpty(testDll));
    //Contract.Requires(!String.IsNullOrEmpty(testMethod));
    //Contract.Requires(!String.IsNullOrEmpty(outFile));

    testDll = Path.GetFullPath(testDll);
    // this and all of the other tests suffer from TOCTOU issues, but they
    // are just advisory.  MSTest is the real gauntlet.
    if (!File.Exists(testDll))
    {
        throw new FileNotFoundException("testDll not found", testDll);
    }

    outFile = Path.GetFullPath(outFile);
    if (File.Exists(outFile) || !Directory.Exists(Path.GetDirectoryName(outFile)))
    {
        throw new InvalidOperationException("outFile already exists or directory does not exist");
    }

    string msTestLoc = GetMsTestPath("12.0"); // 12 == 2013, 11 = 2012, 10 == 2010, 9 == 2008

    // while testDll and outFile are minimally validated, testMethod is a
    // ripe target for injection into the command arguments.  Validation
    // would be appropriate.
    var psi = new ProcessStartInfo(msTestLoc, string.Format(
        "/testcontainer:\"{0}\" /test:{1} /unique /resultsfile:\"{2}\"",
        testDll, testMethod, outFile))
    {
        UseShellExecute = false,
        CreateNoWindow = true,
        RedirectStandardError = true,
        RedirectStandardOutput = true
    };
    var proc = Process.Start(psi);

    var errorOutput = new StringBuilder();
    proc.ErrorDataReceived += (_1, args) => errorOutput.AppendLine(args.Data);
    proc.OutputDataReceived += (_1, args) => errorOutput.AppendLine(args.Data);
    proc.BeginErrorReadLine();
    proc.BeginOutputReadLine();

    proc.WaitForExit();
    // we would check the return code here, but they don't seem to be documented
    if (!File.Exists(outFile))
    {
        throw new InvalidOperationException("mstest.exe did not produce an "
            + "output file:\r\n" + errorOutput.ToString());
    }
}

private static string GetMsTestPath(string vsVersion)
{
    //Contract.Ensures(Contract.Result<string>() != null);
    //Contract.Requires(!string.IsNullOrEmpty(vsVersion));

    using (var hklm = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry32))
    using (var vsReg = hklm.OpenSubKey(@"SOFTWARE\Wow6432Node\Microsoft\VisualStudio\" + vsVersion))
    {
        var res = (string)vsReg.GetValue("InstallDir");
        if (res == null || !Directory.Exists(res))
        {
            throw new InvalidOperationException("VS install path not found");
        }

        var msbuildPath = Path.Combine(res, "mstest.exe");
        if (!File.Exists(msbuildPath))
        {
            throw new InvalidOperationException("MSTest not found");
        }

        return msbuildPath;
    }
}