Как поместить данные в cin из строки

Мне нужно написать тесты (используя google testing framework) для небольшой учебной программы, написанной не мной. (это просто небольшая консольная игра, которая может получать режимы из командной строки или просто получать их во время выполнения)
Есть проблема: я не могу изменить код souce, но почти во всех методах используются cout и cin. и мой вопрос «как ответить на запросы (cin) программы во время тестирования (что-то вроде получения данных для cin из строки)?».

3

Решение

Предполагая, что вы можете контролировать 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 читать из потока строк. Это может быть и любой другой потоковый буфер.

5

Другие решения

Насколько я понимаю, вам нужно выполнить следующее:

  1. Запустить / запустить целевой исполняемый файл (игру).
  2. Отправить тестовые данные в целевой исполняемый файл.
  3. Получить вывод из целевого исполняемого файла.
  4. Сравните результат с ожидаемыми результатами.

Стандартный язык C ++ не имеет стандартных средств связи с другими программами. Вам понадобится помощь операционной системы (которую вы не указали).

С помощью только C ++ или же без особых вызовов ОС, Я предлагаю:

  1. Запись тестового ввода в файл.
  2. Запустите исполняемый файл, отправив тестовый входной файл в качестве входных данных и отправив
    вывод в файл результатов.
  3. Прочитайте и проанализируйте файл результатов.

В противном случае, найдите в своей ОС OS API, чтобы узнать, как записывать драйверы перенаправления ввода / вывода.

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

Вы можете улучшить тестируемость ваших классов, не используя cin а также cout непосредственно. Вместо этого используйте istream& а также ostream& передать входной источник и выходной приемник в качестве параметров. Это случай внедрения зависимости. Если вы сделаете это, вы можете передать в std::stringstream вместо cin, так что вы можете предоставить указанный ввод и получить на выходе из вашей тестовой среды.

Тем не менее, вы можете достичь аналогичного эффекта, превратив Cin и Cout в stringstreamс (по крайней мере временно). Для этого установите std :: stringbuf (или «позаимствуйте» один из std::stringstream) и использовать cin.rdbuf(my_stringbuf_ptr) изменить streambuf использован 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();
1
По вопросам рекламы ammmcru@yandex.ru