3

我需要为不是我编写的小型学习程序编写测试(使用谷歌测试框架)。(它只是一个小型控制台游戏,可以从命令行获取模式或仅在运行时获取模式) 有一个问题:我无法更改源代码,但几乎所有方法都使用了 cout 和 cin。我的问题是“如何在测试时回答程序的请求(cin)(例如从字符串获取 cin 的数据)? ”。

4

4 回答 4

7

假设您可以控制main()(或在要测试的函数之前调用的其他函数),您可以更改std::cin读取位置和std::cout写入位置:

int main(int ac, char* av[]) {
    std::streambuf* orig = std::cin.rdbuf();
    std::istringstream input("whatever");
    std::cin.rdbuf(input.rdbuf());
    // tests go here
    std::cin.rdbuf(orig);
}

(同样对于std::cout

这个例子保存了原始的流缓冲区,std::cin以便在离开之前可以替换它main()。然后它设置std::cin为从字符串流中读取。它也可以是任何其他流缓冲区。

于 2013-01-27T18:14:29.180 回答
1

我的理解是您需要执行以下操作:

  1. 启动/启动目标可执行文件(游戏)。
  2. 将测试数据发送到目标可执行文件。
  3. 从目标可执行文件获取输出。
  4. 将输出与预期结果进行比较。

标准 C++ 语言没有与其他程序通信的标准工具。您将需要操作系统的帮助(您没有指定)。

仅使用C++不使用特定于操作系统的调用,我建议:

  1. 将测试输入写入文件。
  2. 运行可执行文件,将测试输入文件作为输入通过管道传输,并将输出通过管道传输到结果文件。
  3. 读取并分析结果文件。

否则,请搜索您的操作系统 API 以了解如何写入 I/O 重定向驱动程序。

于 2013-01-27T18:10:34.870 回答
1

我知道你说你不能修改代码,但我会尽可能地回答这个问题。现实世界通常允许(小的)修改以适应测试。

一种方法是将需要外部输入(数据库、用户输入、套接字等)的调用包装在虚拟的函数调用中,以便您可以模拟它们。(示例如下)。但首先,关于测试的书籍推荐。 Working Effectively with Legacy Code是一本伟大的书,用于测试不仅限于遗留代码的技术。

class Foo {
public:
   bool DoesSomething() 
   {
      string usersInput;
      cin >> usersInput;
      if (usersInput == "foo") { return true; }
      else { return false; }
   }
};

会变成:

class Foo
{
public:
   bool DoesSomething() {
      string usersInput = getUserInput();
      if (usersInput == "foo") { return true; }
      else { return false; }
   }

protected:
   virtual std::string getUserInput() {
      string usersInput;
      cin >> usersInput;
      return usersInput;
   }

};

class MockFoo : public Foo {
public:
   void setUserInput(std::string input) { m_input = input }
   std::string getUserInput() {
      return m_input;
   }
};

TEST(TestUsersInput)
{
   MockFoo foo;
   foo.setUserInput("SomeInput");
   CHECK_EQUAL(false, foo.DoesSomething());

   foo.setUserInput("foo");
   CHECK_EQUAL(true, foo.DoesSomething());
}
于 2013-01-27T18:13:01.107 回答
1

cin您可以通过不直接使用and来提高类的可测试性cout。而是使用istream&andostream&将输入源和输出接收器作为参数传递。这是一个依赖注入的例子。如果你这样做,你可以传入 astd::stringstream而不是cin,这样你就可以提供指定的输入并获取测试框架的输出。

也就是说,您可以通过将 cin 和 cout 转换为stringstreams 来实现类似的效果(至少暂时如此)。为此,请设置一个 std::stringbuf (或从 a 中“借用”一个std::stringstream)并使用cin.rdbuf(my_stringbuf_ptr)来更改streambuf使用的 by cin。您可能希望在测试拆解中恢复此更改。为此,您可以使用如下代码:

stringbuf test_input("One line of input with no newline", ios_base::in);
stringbuf test_output(ios_base::out);
streambuf * const cin_buf = cin.rdbuf(&test_input);
streambuf * const cout_buf = cout.rdbuf(&test_output);
test_func(); // uses cin and cout
cout.rdbuf(cout_buf);
cin.rdbuf(cin_buf);
string test_output_text = test_output.str();
于 2013-01-27T18:32:26.663 回答