vak: (Default)
[personal profile] vak
Навеяло недавним достижением [personal profile] spamsink: восстановлением исходников игры "Посадка на Луну" с БЭСМ-6.

https://github.com/besm6/bega-re/blob/master/landing.pas

Пусть у нас есть диалоговое приложение на Си++ с текстовым интерфейсом. Приложение запрашивает построчный ввод из std::cin и выдаёт результаты на std::cout. Условно говоря, вызов выглядит следующим образом:
application(std::cin, std::cout);
Схематично, работает оно так:
void application(std::istream &input, std::ostream &output)
{
output << "something\n";

while (!input.eof()) {
std::string line;
getline(input, line);

std::string result = something(line);
output << result;
}
}
Теперь стоит задача покрыть имеющуюся реализацию тестами. Я ж теперь адепт TDD. Хочется иметь возможность делать тесты (с применением Catch) вида:
send("foo\n");
std::string reply = receive();
REQUIRE(reply == "bar\n");
Как бы вы стали решать эту задачу? Я имею в виду, как средствами Си++ привинтить одно к другому? Чтобы, не модифицируя исходники application(), вызывать и тестировать её из Catch?

Нет, это не задача для собеседования. Тут и опытный человек голову сломает.

Традиционно такие штуки принято делать через Expect, но выглядит такой подход слишком громоздко. Лучше найти решение средствами самого языка Си++.

Date: 2020-08-13 22:00 (UTC)
From: [personal profile] caztd
Нужно же что-то вроде?
MyStreamMockClass mock;
MyAppClass app(mock); 
EXPECT_CALL(mock, GetInputString()).WillOnce(Return("input"));
std::string reply = app.receive();


Конечно вам нужен свой stream-interface wrapper так как ifstream.get() не виртуальный метод.

Date: 2020-08-13 22:23 (UTC)
From: [personal profile] caztd
Какая разница. Вызывайте функцию.
Mock может запомнить список ожидаемых значений.
Не совсем REPL, но для теста достаточно.
Потом можно проверить весь output сразу или тоже сделать мок и задать список ожидаемых строк -- если вам построчно нужно.

Или вам нужно менять ввод в зависимости от вывода?

Date: 2020-08-13 22:52 (UTC)
From: [personal profile] caztd
Ну просто редко кто такую логику в unit test вставляет.
Если это тестовое приложение, тогда моки не помогут,
нужeн pipe или streambuf, как предложили выше.
Что-то типа такого:
https://stackoverflow.com/questions/28356629/connecting-two-streaming-functions-c