【发布时间】:2021-08-13 14:19:55
【问题描述】:
我有一个 Specflow BDD 测试,我在其中检查进程是否正在运行,如果是,则终止它。
这目前发生在以下步骤之一中:
[Given(@"Application ""(.*)"" application runs version ""(.*)""")]
public void WhenApplicationRunsVersion(string publisher, string version)
{
var ApplicationOptions = new ApplicationOptions();
_configuration.GetSection("Application").Bind(ApplicationOptions);
var processRunning = TestHelper.ProcessRunning(publisher);
if (processRunning)
{
TestHelper.KillProcess(publisher);
}
var result = TestHelper.ExecuteShellCommand(ApplicationOptions.FilePath.ToString() + version + "\\",
ApplicationOptions.Filename.ToString(),
timeout: 150000);
processRunning = TestHelper.ProcessRunning(publisher);
processRunning.Should().BeTrue();
}
我想把它拿出来并在BeforeScenario 方法中运行。我在我的 Hooks.cs 文件中创建了这个
[Binding]
public class Hooks
{
[BeforeScenario]
public static void BeforeScenario(ScenarioContext scenarioContext)
{
TestHelper.KillProcess(scenarioContext);
}
}
这是我的测试助手:
public class TestHelper
{
public static async Task<ProcessResult> ExecuteShellCommand(string path, string command, string arguments="", int timeout=1000, bool insertWait=false)
{
var result = new ProcessResult();
using (var process = new Process())
{
process.StartInfo.FileName = path + command;
process.StartInfo.Arguments = arguments;
process.StartInfo.UseShellExecute = false;
process.StartInfo.RedirectStandardInput = true;
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.RedirectStandardError = true;
process.StartInfo.CreateNoWindow = true;
process.StartInfo.WorkingDirectory = Path.GetDirectoryName(path);
var outputBuilder = new StringBuilder();
var outputCloseEvent = new TaskCompletionSource<bool>();
process.OutputDataReceived += (s, e) =>
{
// The output stream has been closed i.e. the process has terminated
if (e.Data == null)
{
outputCloseEvent.SetResult(true);
}
else
{
outputBuilder.AppendLine(e.Data);
}
};
var errorBuilder = new StringBuilder();
var errorCloseEvent = new TaskCompletionSource<bool>();
process.ErrorDataReceived += (s, e) =>
{
// The error stream has been closed i.e. the process has terminated
if (e.Data == null)
{
errorCloseEvent.SetResult(true);
}
else
{
errorBuilder.AppendLine(e.Data);
}
};
bool isStarted;
try
{
isStarted = process.Start();
}
catch (Exception error)
{
// Usually it occurs when an executable file is not found or is not executable
result.Completed = true;
result.ExitCode = -1;
result.Output = error.Message;
isStarted = false;
}
if (isStarted)
{
// Reads the output stream first and then waits because deadlocks are possible
//process.BeginOutputReadLine();
process.BeginErrorReadLine();
if (insertWait)
{
StreamReader reader = process.StandardOutput;
string output = reader.ReadToEnd();
result.Output = output;
// Creates task to wait for process exit using timeout
var waitForExit = WaitForExitAsync(process, timeout);
// Create task to wait for process exit and closing all output streams
var processTask = Task.WhenAll(waitForExit, outputCloseEvent.Task, errorCloseEvent.Task);
// Waits process completion and then checks it was not completed by timeout
if (await Task.WhenAny(Task.Delay(timeout), processTask) == processTask && waitForExit.Result)
{
result.Completed = true;
result.ExitCode = process.ExitCode;
// Adds process output if it was completed with error
if (process.ExitCode != 0)
{
result.Output = $"{outputBuilder}{errorBuilder}";
}
}
else
{
try
{
// Kill hung process
process.Kill();
}
catch
{
}
}
}
}
}
return result;
}
private static Task<bool> WaitForExitAsync(Process process, int timeout)
{
return Task.Run(() => process.WaitForExit(timeout));
}
public struct ProcessResult
{
public bool Completed;
public int? ExitCode;
public string Output;
}
public static void KillProcess(string processName)
{
foreach(Process process in Process.GetProcessesByName(processName))
{
process.Kill();
}
}
public static bool ProcessRunning(string processName)
{
Process[] pname = Process.GetProcessesByName(processName);
if (pname.Length == 0)
{
return false;
}
else
{
return true;
}
}
}
我的问题是我需要进程名称才能运行TestHelper.KillProcess()。如何将它传递给我的 BeforeScenario() 方法?
【问题讨论】:
-
为什么要将其移至
BeforeScenario方法?您希望获得什么? -
您也许可以使用标签来实现这一点。见stackoverflow.com/q/59876532/261050。
-
我先到了 BeforeScenario。这不是必需的。接下来,我要添加类似于 AfterScenario 的内容。我要添加的内容当前有一个场景步骤,因此如果在它失败之前的步骤将不会执行,所以我想移动它以确保它始终运行,所以我仍然会有这个查询。