How to put data in cin from string

风流意气都作罢 提交于 2019-12-23 19:26:23

问题


I need to write tests(using google testing framework) for small study program that was written not by me. (it's just small console game which can get modes from command line or just get it in runtime) There is a problem: I can't change the souce code but there is in almost all methods used cout and cin. and my question is "how to answer on requests (cin) of programm while testing (something like get data for cin from string )?".


回答1:


Assuming you can control main() (or some other function called before the functions to be tested) you can change where std::cin reads from and where std::cout writes to:

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);
}

(likewise for std::cout)

This example saves the original stream buffer of std::cin so it can be replaced before leaving main(). It then sets up std::cin to read from a string stream. It can be any other stream buffer as well.




回答2:


My understanding is you need to perform the following:

  1. Launch / start target executable (the game).
  2. Send test data to target executable.
  3. Obtain output from target executable.
  4. Compare output with expected results.

The standard C++ language has no standard facilities for communicating with other programs. You will need help from the operating system (which you didn't specify).

Using only C++ or without OS specific calls, I suggest:

  1. Writing test input to a file.
  2. Run the executable, piping the test input file as input and piping the output to a results file.
  3. Read and analyze the result file.

Otherwise, search your OS API to find out how to write to the I/O redirection drivers.




回答3:


I know you said you can't modify the code, but I'll answer this as if you can. The real world typically allows (small) modifications to accommodate testing.

One way is to wrap your calls that require external inputs (DB, user input, sockets, etc...) in function calls that are virtual so you can mock them out. (Example below). But first, a book recommendation on testing. Working Effectively with Legacy Code is a great book for testing techniques that aren't just limited to legacy code.

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

Would turn into:

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());
}



回答4:


You can improve testability of your classes by not using cin and cout directly. Instead use istream& and ostream& to pass in the input source and output sink as parameters. This is a case of dependency injection. If you do that, you can pass in a std::stringstream instead of cin, so that you can provide specified input and get at the output from your test framework.

That said, you can achieve a similar effect by turning cin and cout into stringstreams (at least temporarily). To do this, set up a std::stringbuf (or "borrow" one from a std::stringstream) and use cin.rdbuf(my_stringbuf_ptr) to change the streambuf used by cin. You may want to revert this change in test teardown. To do that you can use code like:

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();


来源:https://stackoverflow.com/questions/14550187/how-to-put-data-in-cin-from-string

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!