【发布时间】:2016-01-24 02:29:00
【问题描述】:
我正在为命令行可执行文件编写集成测试驱动程序。我同时控制驱动程序和可执行文件,因此我可以保证它们的行为——例如,可执行文件从不从标准输入读取,它只接受命令行参数,执行它的操作,然后将输出写入文件和标准输出。
我希望同时捕获进程的退出代码和标准输出以进行验证。
这是我正在使用的代码:
#include <Windows.h>
class Pipe {
HANDLE ReadHandle;
HANDLE writehandle;
public:
Pipe() {
SECURITY_ATTRIBUTES saAttr;
saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
saAttr.bInheritHandle = TRUE;
saAttr.lpSecurityDescriptor = NULL;
CreatePipe(&ReadHandle, &writehandle, &saAttr, 0);
}
HANDLE WriteHandle() {
return writehandle;
}
std::string Contents() {
CloseHandle(writehandle);
DWORD dwRead;
CHAR chBuf[1024];
BOOL bSuccess = FALSE;
std::string result;
for (;;)
{
bSuccess = ReadFile(ReadHandle, chBuf, 1024, &dwRead, NULL);
if (!bSuccess) break;
result += std::string(chBuf, chBuf + dwRead);
if (dwRead < 1024)
break;
}
return result;
}
~Pipe() {
CloseHandle(ReadHandle);
}
};
Wide::Driver::ProcessResult Wide::Driver::StartAndWaitForProcess(std::string name, std::vector<std::string> args, Util::optional<unsigned> timeout)
{
ProcessResult result;
Pipe stdoutpipe;
PROCESS_INFORMATION info = { 0 };
STARTUPINFO startinfo = { sizeof(STARTUPINFO) };
std::string final_args = name;
for (auto arg : args)
final_args += " " + arg;
startinfo.hStdOutput = stdoutpipe.WriteHandle();
startinfo.hStdError = INVALID_HANDLE_VALUE;
startinfo.hStdInput = INVALID_HANDLE_VALUE;
startinfo.dwFlags |= STARTF_USESTDHANDLES;
auto proc = CreateProcess(
name.c_str(),
&final_args[0],
nullptr,
nullptr,
TRUE,
NORMAL_PRIORITY_CLASS | CREATE_NO_WINDOW,
nullptr,
nullptr,
&startinfo,
&info
);
if (!proc) {
DWORD dw = GetLastError();
const char* message;
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
nullptr, dw, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&message, 0, nullptr);
std::string err = message;
LocalFree((void*)message);
throw std::runtime_error(err);
}
if (timeout == 0)
timeout = INFINITE;
result.std_out = stdoutpipe.Contents();
if (WaitForSingleObject(info.hProcess, timeout ? *timeout : INFINITE) == WAIT_TIMEOUT)
TerminateProcess(info.hProcess, 1);
DWORD exit_code;
GetExitCodeProcess(info.hProcess, &exit_code);
CloseHandle(info.hProcess);
CloseHandle(info.hThread);
result.exitcode = exit_code;
if (exit_code != 0)
return result;
return result;
}
我有 259 个以这种方式运行的集成测试。有些需要比其他更长的时间。当我运行该套件时,大约 1-3 会失败 - 每次都不同。我在调试器中查看了结果,标准输出在中途被切断。如果我不尝试捕获标准输出,那么所有测试每次都会成功,所以我知道它是基于标准输出捕获的。
指定了超时,但它是一个非常大的 60 秒 - 比正常运行测试所需的时间长得多。我为每个测试生成一个新进程。
如何以更可靠的方式捕获标准输出,而不会出现随机故障?
最后一点,运行套件需要很长时间才能在调试器中捕获故障,因此可能需要一段时间来处理任何获取更多信息的请求。
【问题讨论】: