CppUnit 的多线程实现?

发布于 2024-10-20 16:16:30 字数 170 浏览 2 评论 0原文

有人可以向我指出一个允许在单独的线程中启动测试的 CppUnit 版本吗?

我们的想法是,由于我们的许多测试都需要大量 CPU(但不是多线程,当然,它们是相互独立的),因此它将使我们能够在当今的多核上更快地运行测试机器。目前,运行所有测试大约需要 5 分钟。如果能够将其缩短到 1 或 2 分钟,那就太好了……

Could someone point me to a version of CppUnit that would allow to launch the tests in separate threads?

The idea is that, because many of our tests are quite CPU heavy (but are not multi-thread and, of course, are independant one from the other), it would allow us to run the tests much more quickly on today's multi-core machines. Currently, it takes around 5 minutes to run all the tests. It would be great to be able to reduce this to 1 or 2 minutes...

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

べ繥欢鉨o。 2024-10-27 16:16:30

您认为等待测试完成五分钟是很长的时间!尝试几个小时。我有以下动机。

使用 Boost 线程,CppUnit 线程化非常简单。 CppUnit 已经有一些用于同步的钩子,因此以下内容应该使其线程安全:

class Mutex : public CPPUNIT_NS::SynchronizedObject::SynchronizationObject
{
public:
    void lock() { this->mutex->lock(); }
    void unlock() { this->mutex->unlock(); }
private:
    boost::mutex mutex; 
};

有了这个,您可以修改测试运行器以使 TestResult 线程安全。只需编写类似 CPPUNIT_NS::TestResult testResult(new Mutex); 的内容即可。现在这是一个线程测试套件:

class TestSuiteThreaded : public CPPUNIT_NS::TestSuite
{
public:
    TestSuiteThreaded(std::string name = "", int nThreads = 0)
        : TestSuite(name)
        , nThreads(nThreads ? nThreads : boost::thread::hardware_concurrency())
    {
    }
    void doRunChildTests(CPPUNIT_NS::TestResult *controller)
    {
        ThreadPool pool(this->nThreads);
        for (int i=0; i < getChildTestCount(); ++i)
        {
            pool.add(
                boost::bind(threadFunction, getChildTestAt(i)
                , controller));
        }
    }
private:
    static void threadFunction(
        CPPUNIT_NS::Test *test, 
        CPPUNIT_NS::TestResult *controller)
    {
        test->run(controller);
    }
    const int nThreads;
};

您可能很需要一个宏来轻松使用线程测试套件。您应该能够将 TestSuiteThreaded 套件用作顶级套件或包含同一文本固定装置的多个方法的套件。以下是执行后者的方法 - 将其替换 CPPUNIT_TEST_SUITE_END。其中一些内容是从 CppUnit 粘贴的,因此请尊重许可证

#define CPPUNIT_TEST_SUITE_END_THREADED(n)                                     \
    }                                                                          \
    static CPPUNIT_NS::TestSuite *suite()                                      \
    {                                                                          \
      const CPPUNIT_NS::TestNamer &namer = getTestNamer__();                   \
      std::auto_ptr<CPPUNIT_NS::TestSuite> suite(                              \
         new CPPUNIT_NS::TestSuiteThreaded( namer.getFixtureName(), n));       \
      CPPUNIT_NS::ConcretTestFixtureFactory<TestFixtureType> factory;          \
      CPPUNIT_NS::TestSuiteBuilderContextBase context( *suite.get(),           \
                               namer,                                          \
                               factory );                                      \
      TestFixtureType::addTestsToSuite( context );                             \
      return suite.release();                                                  \
    }                                                                          \
  private: /* dummy typedef so that the macro can still end with ';'*/         \
    typedef int CppUnitDummyTypedefForSemiColonEnding__

现在有一个ThreadPool的小问题。我尝试使用各种公开的方法但没有成功。我的公司有一个,但我无法在这里发布。因此,您可以自己动手 - 在 Boost 的帮助下,制作线程池非常简单且有趣。这是 TestSuiteThreaded 所期望的接口:

class ThreadPool
{
public:
    // Create thread pool, launching n worker threads
    ThreadPool(unsigned n); 

    // Join all worker threads and clean up
    ~ThreadPool();

    // You can have add() do one of two things.  Both will work:
    // Either: push a new task to the back of the threadpool's work queue
    // Or: block until a worker is free then assign task to that thread
    void add(boost::function0<void> task);
};

我将其作为练习留给读者。玩得开心!

You think five minutes is a long time to wait for tests to complete! Try several hours. I had motivation for the following.

Using Boost threads, CppUnit threading is pretty easy. CppUnit already has some hooks for synchronization so the following should make it thread safe:

class Mutex : public CPPUNIT_NS::SynchronizedObject::SynchronizationObject
{
public:
    void lock() { this->mutex->lock(); }
    void unlock() { this->mutex->unlock(); }
private:
    boost::mutex mutex; 
};

With this, you can modify your test runner to make your TestResult thread safe. Just write something like CPPUNIT_NS::TestResult testResult(new Mutex);. Now here's a threaded test suite:

class TestSuiteThreaded : public CPPUNIT_NS::TestSuite
{
public:
    TestSuiteThreaded(std::string name = "", int nThreads = 0)
        : TestSuite(name)
        , nThreads(nThreads ? nThreads : boost::thread::hardware_concurrency())
    {
    }
    void doRunChildTests(CPPUNIT_NS::TestResult *controller)
    {
        ThreadPool pool(this->nThreads);
        for (int i=0; i < getChildTestCount(); ++i)
        {
            pool.add(
                boost::bind(threadFunction, getChildTestAt(i)
                , controller));
        }
    }
private:
    static void threadFunction(
        CPPUNIT_NS::Test *test, 
        CPPUNIT_NS::TestResult *controller)
    {
        test->run(controller);
    }
    const int nThreads;
};

You may well need a macro for easy use of the threaded test suite. You should be able to use TestSuiteThreaded suite either as a top level suite or a suite comprising multiple methods of the same text fixture. Here's how you do the latter - put this in place of CPPUNIT_TEST_SUITE_END. Some of this is pasted from CppUnit so please respect the license:

#define CPPUNIT_TEST_SUITE_END_THREADED(n)                                     \
    }                                                                          \
    static CPPUNIT_NS::TestSuite *suite()                                      \
    {                                                                          \
      const CPPUNIT_NS::TestNamer &namer = getTestNamer__();                   \
      std::auto_ptr<CPPUNIT_NS::TestSuite> suite(                              \
         new CPPUNIT_NS::TestSuiteThreaded( namer.getFixtureName(), n));       \
      CPPUNIT_NS::ConcretTestFixtureFactory<TestFixtureType> factory;          \
      CPPUNIT_NS::TestSuiteBuilderContextBase context( *suite.get(),           \
                               namer,                                          \
                               factory );                                      \
      TestFixtureType::addTestsToSuite( context );                             \
      return suite.release();                                                  \
    }                                                                          \
  private: /* dummy typedef so that the macro can still end with ';'*/         \
    typedef int CppUnitDummyTypedefForSemiColonEnding__

Now there is the small matter of a ThreadPool. I tried using various publicly available ones with no success. My company has one but I'm unable to publish it here. So roll your own - thread pools are pretty easy and fun to make, with help from Boost. Here is the interface expected by TestSuiteThreaded:

class ThreadPool
{
public:
    // Create thread pool, launching n worker threads
    ThreadPool(unsigned n); 

    // Join all worker threads and clean up
    ~ThreadPool();

    // You can have add() do one of two things.  Both will work:
    // Either: push a new task to the back of the threadpool's work queue
    // Or: block until a worker is free then assign task to that thread
    void add(boost::function0<void> task);
};

I leave this as an exercise for the reader. Have fun!

千纸鹤 2024-10-27 16:16:30

考虑到这个问题你得到了多少答案,特别是与赞成票数相比,我怀疑有人已经做出了一个好的多线程单元测试框架,无论它是多么伟大的想法。对于某人来说,这似乎是一个绝佳的机会,可以通过开发一些非常有用的东西来扬名立万。

Given how many answers to this question you've gotten, especially as compared with the number of upvotes, I doubt anybody has made a good multi-threaded unit testing framework, no matter how great an idea it is. This looks like a great opportunity for someone to make a name for themselves developing something inordinately useful.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文