有一天,我决定我需要了解Windows平台上的C ++的testing驱动开发(使用Visual Studio 2010 Premium)。
在研究boost的unit testing框架之前,我看了一下。 我应该说,我select了boostpro.com的发布(目前是1.44,如果我没有记错的话)。 这有一个静态库的构build,所以我不使用我的testing中的DLL。
Boost的unit testing文档讨论了如何从testing套件中分离代码,这似乎是合理的。 但是,你必须处理从你现在独立的testing套件项目中引用你的代码的问题。
所以我有一个库项目,我想testing(但我仍然不知道如何编写可以引用.exe项目的testing…)
所以我在我的解决scheme中创build了一个单独testing项目。 我添加了下面的代码:
#include "stdafx.h" #define BOOST_TEST_MODULE Crash #include <boost/test/unit_test.hpp> #include "LameEncoder.h" BOOST_AUTO_TEST_SUITE(CrashTestSuite) BOOST_AUTO_TEST_CASE(EncoderAvailable) { using namespace Crash::SystemDevices::Audio::Compressors::LameEncoder; HRESULT hr = S_OK; CComPtr <IBaseFilter> spEncoder; hr = spEncoder.CoCreateInstance( CLSID_LAMEDShowFilter ); if( spEncoder.p ) spEncoder.Release(); BOOST_CHECK_EQUAL( hr, S_OK ); } BOOST_AUTO_TEST_CASE(ProfilesGenerated) { using namespace Crash::SystemDevices::Audio::Compressors::LameEncoder; BOOST_CHECK_EQUAL ( EncoderProfiles.size(), 6 ); } BOOST_AUTO_TEST_SUITE_END()
我静态链接到我的“崩溃”库项目输出,然后我添加了以下后生成事件来获取报告后构build:
"$(TargetDir)\$(TargetName).exe" --result_code=no --report_level=short
后构build输出如下所示:
1>------ Build started: Project: UnitTests, Configuration: Debug Win32 ------ 1> UnitTests.cpp 1> UnitTests.vcxproj -> F:\Projects\Crash\trunk\Debug\UnitTests.exe 1> Running 2 test cases... 1> f:/projects/crash/trunk/unittests/unittests.cpp(19): error in "EncoderAvailable": check hr == ((HRESULT)0L) failed [-2147221008 != 0] 1> 1> Test suite "Crash" failed with: 1> 1 assertion out of 2 passed 1> 1 assertion out of 2 failed 1> 1 test case out of 2 passed 1> 1 test case out of 2 failed
我期望EncoderAvailabletesting失败,因为我还没有初始化线程的COM公寓。 我假设我不能使用自动testing,而是我需要用testing来replace自动testing,我在主函数中手动定义自己,并在主函数中执行我的CoInitializeEx()调用。
我读过这里 ,你可以定义入口点并注册你自己的函数,所以我给了这个一个去:
#include "stdafx.h" #include <boost/test/unit_test.hpp> using namespace boost::unit_test; #include "LameEncoderTests.h" test_suite* init_unit_test_suite( int argc, char* argv[] ) { CoInitializeEx(NULL, COINIT_MULTITHREADED); framework::master_test_suite(). add( BOOST_TEST_CASE( &LameEncoderAvailable ) ); framework::master_test_suite(). add( BOOST_TEST_CASE( &LameEncoderProfilesGenerated ) ); CoUninitialize(); return 0; }
这是build立ouptut:
1>------ Build started: Project: UnitTests, Configuration: Debug Win32 ------ 1> UnitTests.cpp 1> UnitTests.vcxproj -> F:\Projects\Crash\trunk\Debug\UnitTests.exe 1> Running 2 test cases... 1> f:/projects/crash/trunk/unittests/lameencodertests.h(17): error in "LameEncoderAvailable": check hr == ((HRESULT)0L) failed [-2147221008 != 0] 1> 1> Test suite "Master Test Suite" failed with: 1> 1 assertion out of 2 passed 1> 1 assertion out of 2 failed 1> 1 test case out of 2 passed 1> 1 test case out of 2 failed 1> ========== Build: 1 succeeded, 0 failed, 0 up-to-date, 0 skipped ==========
那个testing失败的第一个testingLameEncoderAvailable,这是下面的简单function:
void LameEncoderAvailable() { using namespace Crash::SystemDevices::Audio::Compressors::LameEncoder; HRESULT hr = S_OK; CComPtr<IBaseFilter> spEncoder; hr = spEncoder.CoCreateInstance( CLSID_LAMEDShowFilter ); if( spEncoder.p ) spEncoder.Release(); BOOST_CHECK_EQUAL( hr, S_OK ); }
任何人都可以告诉我在哪里做CoInitializeEx()调用的正确位置 – 我不认为我应该这样做一次每个testing – 它应该只做一次线程…
至于testingexe项目,我想你可以指定一个单独的main.cpp(testmain.cpp或其他),并从构build中排除你真正的main.cpp来访问你的代码。 如果有人知道这个更优雅的解决scheme,我会很想听到…
使用全球夹具 。 Fixtures是为每个测试设置初始化/关闭代码的好方法。 全局设备可以让你为整个测试套件定义初始化/关闭代码。
未经测试,但会在构造函数调用CoInitializeEx()的全局变量帮助吗?
为什么不为每个测试做CoInitialize,CoUnitialize?
在同一线程上对CoInitialize或CoInitializeEx的后续调用将成功,只要它们不尝试更改并发模型,但将返回S_FALSE。
编辑:
假设测试确实是同时执行的。 一种方法是拥有一个容纳RAII CoInitialize / CoUnitialize对象的thread_specific容器。
你不需要使用init_unit_test_suite,因为这个函数是在任何测试运行之前执行的。
你确实想使用全局夹具。 调用CoInitializeEx(NULL,COINIT_MULTITHREADED); 在构造函数和CoUnInitializeEx()中; 在析构函数中