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;
}
}
我创建了一个 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;
}
}