如何使用googletest捕获stdout / stderr?

问题描述 投票:40回答:5

使用googletest框架时是否可以捕获stdout和stderr?

例如,我想调用一个将错误写入控制台(stderr)的函数。现在,在测试中调用函数时,我想断言那里没有输出。

或者,也许我想测试错误行为,并希望在我(故意)产生错误时断言某个字符串被打印。

c++ unit-testing stdout stderr googletest
5个回答
30
投票

我之前使用过此片段,在测试输出时将cout调用重定向到字符串流。希望它可能会引发一些想法。我之前从未使用过googletest。

// This can be an ofstream as well or any other ostream
std::stringstream buffer;

// Save cout's buffer here
std::streambuf *sbuf = std::cout.rdbuf();

// Redirect cout to our stringstream buffer or any other ostream
std::cout.rdbuf(buffer.rdbuf());

// Use cout as usual
std::cout << "Hello World";

// When done redirect cout to its old self
std::cout.rdbuf(sbuf);

在重定向回原始输出之前,请使用google测试检查缓冲区中的输出。


69
投票

Googletest为此提供了以下功能:

testing::internal::CaptureStdout();
std::cout << "My test";
std::string output = testing::internal::GetCapturedStdout();

2
投票

避免必须这样做总是一个很好的设计理念。如果你真的想这样做,下面的工作:

#include <cstdio>
#include <cassert>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <iostream>

int main() {
   int fd = open("my_file.log", O_WRONLY|O_CREAT|O_TRUNC, 0660);
   assert(fd >= 0);
   int ret = dup2(fd, 1);
   assert(ret >= 0);
   printf("This is stdout now!\n");
   std::cout << "This is C++ iostream cout now!" << std::endl;
   close(fd);
}

要使用stderr而不是stdout,将dup2的第二个参数更改为2.对于不通过文件进行捕获,您可以使用管道对。


1
投票

而不是这样做,使用依赖注入来删除std::cout的直接使用。在您的测试代码中,使用类std:ostringstream的模拟对象作为模拟对象而不是真正的std::cout

所以不是这样的:

 void func() {
    ...
    std::cout << "message";
    ...
 }

 int main (int argc, char **argv) {
    ...
    func();
    ...
 }

拥有这个:

 void func(std::ostream &out) {
    ...
    out << "message";
    ...
 }

 int main(int argc, char **argv) {
    ...
    func(std::cout);
    ...
 }

0
投票

我们正在完全按照您的意思行事。

首先我们创建了一些宏:

    #define CAPTURE_STDOUT StdoutRedirect::instance().redirect();
    #define RELEASE_STDOUT StdoutRedirect::instance().reset();
    #define ASSERT_INFO( COUNT, TARGET )   \
      ASSERT_PRED_FORMAT2(OurTestPredicates::AssertInfoMsgOutput, TARGET, COUNT );

请参阅此答案以捕获stdout和stderr:https://stackoverflow.com/a/5419409/9796918只需使用他们的BeginCapture(),EndCapture()代替我们的redirect()和reset()。

在AssertInfoMsgOutput方法中:

    AssertionResult OurTestPredicates::AssertInfoMsgOutput( const char* TARGET,
        const char* d1,
        const char* d2,
        int         COUNT )
    {
      int count = 0;
      bool match = false;
      std::string StdOutMessagge = GetCapture();
      // Here is where you process the stdout/stderr info for the TARGET, and for
      // COUNT instances of that TARGET message, and set count and match
      // appropriately
      ...
      if (( count == COUNT ) && match )
      {
        return ::testing::AssertionSuccess();
      }
      return :: testing::AssertionFailure() << "not found";
    }

现在在您的单元测试中,只需将您要捕获的调用包装为stdout / stderr:

    CAPTURE_STDOUT
    // Make your call to your code to test / capture here
    ASSERT_INFO( 1, "Foo bar" );
    RELEASE_STDOUT

0
投票

基于Wgaffa的答案,我制作了这个辅助类,可以用std::coutstd::cerr构建:

class CaptureHelper
{
public:
  CaptureHelper(std::ostream& ioStream)
    : mStream(ioStream),
    mIsCapturing(false)
  { }

  ~CaptureHelper()
  {
    release();
  }

  void capture()
  {
    if (!mIsCapturing)
    {
      mOriginalBuffer = mStream.rdbuf();
      mStream.rdbuf(mRedirectStream.rdbuf());
      mIsCapturing = true;
    }
  }

  std::string release()
  {
    if (mIsCapturing)
    {
      std::string wOutput = mRedirectStream.str();
      mStream.rdbuf(mOriginalBuffer);
      mIsCapturing = false;
      return wOutput;
    }
  }

private:
  std::ostream& mStream;
  bool mIsCapturing;
  std::stringstream mRedirectStream;
  std::streambuf* mOriginalBuffer;

};
© www.soinside.com 2019 - 2024. All rights reserved.