有人能指出我允许在单独的线程中启动测试的 CppUnit 版本吗?
这个想法是,因为我们的许多测试都占用大量 CPU(但不是多线程的,当然,它们相互独立),这将使我们能够在当今的多核上更快地运行测试机器。目前,运行所有测试大约需要 5 分钟。能把这个时间缩短到 1 到 2 分钟就好了……
有人能指出我允许在单独的线程中启动测试的 CppUnit 版本吗?
这个想法是,因为我们的许多测试都占用大量 CPU(但不是多线程的,当然,它们相互独立),这将使我们能够在当今的多核上更快地运行测试机器。目前,运行所有测试大约需要 5 分钟。能把这个时间缩短到 1 到 2 分钟就好了……
你认为五分钟等待测试完成是很长的时间!尝试几个小时。我有以下动机。
使用 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);
};
我把这个作为练习留给读者。玩得开心!
考虑到您对这个问题有多少答案,尤其是与赞成票的数量相比,我怀疑是否有人制作了一个好的多线程单元测试框架,无论它是多么棒的想法。对于某人来说,这似乎是一个为自己开发非常有用的东西而出名的好机会。