3

私が書いたものではない小さな学習プログラムのテストを(Googleテストフレームワークを使用して)書く必要があります。(コマンド ラインからモードを取得するか、実行時に取得するだけの小さなコンソール ゲームです) 問題があります: ソース コードを変更することはできませんが、ほとんどすべてのメソッドで 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

cinand をcout直接使用しないことで、クラスのテスト容易性を向上させることができます。代わりにistream&andostream&を使用して、入力ソースと出力シンクをパラメーターとして渡します。これは、依存性注入のケースです。その場合、 のstd::stringstream代わりに a を渡すcinことができるため、指定された入力を提供して、テスト フレームワークからの出力を取得できます。

とはいえ、cin と cout をstringstreams に (少なくとも一時的に) 変更することで、同様の効果を得ることができます。これを行うには、 std::stringbuf を設定 (または から「借用」std::stringstream) し、 を使用して使用されるcin.rdbuf(my_stringbuf_ptr)を変更します。テスト ティアダウンでこの変更を元に戻すことができます。これを行うには、次のようなコードを使用できます。streambufcin

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 に答える
1

私の理解では、次のことを実行する必要があります。

  1. ターゲットの実行可能ファイル (ゲーム) を起動/開始します。
  2. テスト データをターゲット実行可能ファイルに送信します。
  3. ターゲット実行可能ファイルから出力を取得します。
  4. 出力を期待される結果と比較します。

標準 C++ 言語には、他のプログラムと通信するための標準機能がありません。オペレーティング システム (指定しなかったもの) からのヘルプが必要になります。

C++ のみを使用するか、OS 固有の呼び出しを使用せずに、次のことをお勧めします。

  1. テスト入力をファイルに書き込みます。
  2. 実行可能ファイルを実行し、テスト入力ファイルを入力としてパイプし、出力を結果ファイルにパイプします。
  3. 結果ファイルを読み取って分析します。

それ以外の場合は、OS API を検索して、I/O リダイレクション ドライバーへの書き込み方法を見つけてください。

于 2013-01-27T18:10:34.870 に答える
1

コードを変更できないとおっしゃいましたが、できるかのようにお答えします。現実の世界では、通常、テストに対応するために (小さな) 変更が許可されています。

1 つの方法は、外部入力 (DB、ユーザー入力、ソケットなど) を必要とする呼び出しを仮想の関数呼び出しでラップして、それらをモックアウトできるようにすることです。(下の例)。しかし、最初に、テストに関する本をお勧めします。 「レガシー コードを効果的に使用する」は、レガシー コードだけに限定されない手法をテストするための優れた本です。

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 に答える