Zer*_*ero 17 c++ unit-testing boost-asio
如果可能的话,你如何模拟在单元测试中触发升压定时器的时间?
例如,是否可以实现以下内容:
#include <iostream>
#include <boost/asio.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
void print(const boost::system::error_code& /*e*/)
{
std::cout << "Hello, world!\n";
}
int main()
{
boost::asio::io_service io; // Possibly another class needed here, or a way of setting the clock to be fake
boost::asio::deadline_timer t(io, boost::posix_time::hours(24));
t.async_wait(&print);
io.poll(); // Nothing should happen - no handlers ready
// PSEUDO-CODE below of what I'd like to happen, jump ahead 24 hours
io.set_time(io.get_time() + boost::posix_time::hours(24));
io.poll(); // The timer should go off
return 0;
}
Run Code Online (Sandbox Code Playgroud)
更新感谢您的所有答案,他们提供了对问题的深入见解.我提供了自己的答案(SSCCE),但没有提供的帮助就无法做到.
该basic_deadline_timer
模板有一个特点,你可以用它来提供自己的时钟参数.Boost Asio的作者有一篇博客文章,展示了如何做到这一点.这是帖子的一个例子:
class offset_time_traits
: public asio::deadline_timer::traits_type
{
public:
static time_type now()
{
return add(asio::deadline_timer::traits_type::now(), offset_);
}
static void set_now(time_type t)
{
offset_ =
subtract(t, asio::deadline_timer::traits_type::now());
}
private:
static duration_type offset_;
};
typedef asio::basic_deadline_timer<
boost::posix_time::ptime, offset_time_traits> offset_timer;
Run Code Online (Sandbox Code Playgroud)
也许您可以offset_timer
在整个应用程序中使用类似的东西,但只能set_now()
在运行测试时调用?
SSCCE,基于@free_coffee 发布的链接:
#include <boost/asio.hpp>
#include <boost/optional.hpp>
class mock_time_traits
{
typedef boost::asio::deadline_timer::traits_type source_traits;
public:
typedef source_traits::time_type time_type;
typedef source_traits::duration_type duration_type;
// Note this implemenation requires set_now(...) to be called before now()
static time_type now() { return *now_; }
// After modifying the clock, we need to sleep the thread to give the io_service
// the opportunity to poll and notice the change in clock time
static void set_now(time_type t)
{
now_ = t;
boost::this_thread::sleep_for(boost::chrono::milliseconds(2));
}
static time_type add(time_type t, duration_type d) { return source_traits::add(t, d); }
static duration_type subtract(time_type t1, time_type t2) { return source_traits::subtract(t1, t2); }
static bool less_than(time_type t1, time_type t2) { return source_traits::less_than(t1, t2); }
// This function is called by asio to determine how often to check
// if the timer is ready to fire. By manipulating this function, we
// can make sure asio detects changes to now_ in a timely fashion.
static boost::posix_time::time_duration to_posix_duration(duration_type d)
{
return d < boost::posix_time::milliseconds(1) ? d : boost::posix_time::milliseconds(1);
}
private:
static boost::optional<time_type> now_;
};
boost::optional<mock_time_traits::time_type> mock_time_traits::now_;
typedef boost::asio::basic_deadline_timer<
boost::posix_time::ptime, mock_time_traits> mock_deadline_timer;
void handler(const boost::system::error_code &ec)
{
std::cout << "Handler!" << std::endl;
}
int main()
{
mock_time_traits::set_now(boost::posix_time::time_from_string("2013-01-20 1:44:01.000"));
boost::asio::io_service io_service;
mock_deadline_timer timer(io_service, boost::posix_time::seconds(5));
timer.async_wait(handler);
std::cout << "Poll 1" << std::endl;
io_service.poll();
mock_time_traits::set_now(mock_time_traits::now() + boost::posix_time::seconds(6));
std::cout << "Poll 2" << std::endl;
io_service.poll();
std::cout << "Poll 3" << std::endl;
io_service.poll();
return 0;
}
// Output
Poll 1
Poll 2
Handler!
Poll 3
Run Code Online (Sandbox Code Playgroud)
感谢 @free_coffee 提供了boost asio 创建者博客条目的链接。上面稍作修改(我相信略有改进)。通过不使用系统时钟上的偏移,您可以完全控制计时器:除非您明确地将时间向前设置超过计时器,否则它们不会触发。
可以通过使部件可配置来改进该解决方案this_thread::sleep
。请注意,to_posix_duration
[ 1 ] 中描述的 hack 需要使用比sleep
.
对我来说,这种方法仍然有点神奇,因为time_traits
没有很好的记录,特别是 hackto_posix_duration
带有一点巫毒的味道。我想这只是归结为对deadline_timer
实现的深入了解(我没有)。
归档时间: |
|
查看次数: |
3896 次 |
最近记录: |