Прежде всего, мне нужно немного отклонить ваш вопрос. Не создавайте такие интерфейсы. Всякий раз, когда объект был создан, все его функции должны быть разрешены до истечения срока его жизни. Неожиданные ограничения времени жизни, такие как «init(), должны быть вызваны до write()», или еще хуже «всегда вызывайте close(), прежде чем деструктор« не может быть проверен компилятором и, следовательно, подвержен ошибкам.
Поэтому я не думаю, что вы должны попытаться решить эту проблему в тесте, но в разработке тестируемого кода. Всякий раз, когда трудно написать тест, это уверенная ставка, что ваши интерфейсы испорчены.
Мое предложение состоит в том, чтобы отделить время и письмо. Создайте класс таймера, например, например. это одна:
#include <memory>
#include <chrono>
template<typename T>
class Timer {
private:
std::chrono::milliseconds time_to_live;
std::shared_ptr<T> timed_object;
public:
template<typename... Arg>
Timer(std::chrono::milliseconds ttl, Arg... args):
time_to_live{ttl},
timed_object{std::make_shared<T>(args...)} {};
std::weak_ptr<T> get() { return {timed_object}; };
// ...
// when the defined time is over, timed_object will be set to nullptr somehow.
};
Используйте это так:
#include <chrono>
#include <iostream>
#include <fstream>
int main(int, char**)
{
using namespace std::literals::chrono_literals;
auto timed_ostream = Timer<std::ofstream>{42ms, "filename"};
if(!timed_ostream.get().expired()) {
// os is a shared_ptr. That guarantees, that the ostream will not
// be closed while you are still writing.
auto os = timed_ostream.get().lock();
(*os) << "whatever";
} // now os will be destroyed. The ofstream might be destroyed
// as well now, when the 42ms are over.
} // OK, here we destroy the timer and therefore the ofstream,
// if it is still alive.
С этим интерфейсом вы можете легко написать простой тест, с чем-то другим, чем в ostream, например, a int:
#include <chrono>
#include <cassert>
using namespace std::literals::chrono_literals;
void test_timed_object_valid_after_init()
{
auto clock = std::chrono::high_resolution_clock{};
auto start = clock.now();
auto timed_int = Timer<int>{2000ms,42}; // valid for 2000ms
assert(timed_int.get().expired()); // should still be here
} // The timer will be destroyed here. That destroys the shared_ptr
// and the object as well. The long lifetime does not matter.
void test_timed_object_invalid_after_time()
{
auto clock = std::chrono::high_resolution_clock{};
auto start = clock.now();
auto timed_int = Timer<int>{1ms,42}; // valid for 1ms
// you did not want sleep(), so we do busy waiting.
// Prefer usleep() instead.
// busy wait 1ms as exactly as possible.
while(clock.now() - start < 1ms) {}
assert(timed_int.get().expired()); // should be gone now.
}
Обратите внимание, что каждая тестовая система проверяет один сценарий здесь. Не пытайтесь проверить два требования в одном тестовом случае. Затем вам нужно либо потратить долгий срок службы, чтобы ваш объект мог безопасно проверять, что он есть после инициализации, либо выберите короткий срок, чтобы проверить, что он ушел впоследствии.
Остерегайтесь: весь код в этом сообщении должен компилироваться, но, возможно, все еще могут быть ошибки. Они оставлены как упражнение для ученика ;-)