你怎么嘲笑加速计时器的时间?

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),但没有提供的帮助就无法做到.

fre*_*fee 8

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()在运行测试时调用?


Zer*_*ero 1

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实现的深入了解(我没有)。