CoInitializeEx для повышения :: test :: unit_test - PullRequest
2 голосов
/ 07 марта 2011

На днях я решил, что мне нужно знать о тестовой разработке для C ++ на платформе Windows (с использованием Visual Studio 2010 Premium).

Я осмотрелся, прежде чем остановился на тестировании фреймворка для буст-тестов. Я должен сказать, что я выбрал релиз boostpro.com (текущий 1.44, если я правильно помню). Это сборка статической библиотеки, поэтому я не использую DLL в своих тестах.

В документации модульных тестов Boost говорится об отделении вашего кода от набора тестов, что представляется разумным. Но тогда вы должны решить проблему ссылки на ваш код из вашего теперь отдельного проекта набора тестов.

Итак, у меня есть проект библиотеки, который я хочу протестировать (но я все еще не уверен, как написать тесты, которые могут ссылаться на проект .exe ...)

Итак, я создал отдельный проект в своем решении, который называется модульные тесты. Я добавил следующий код:

#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()

Я статически связываюсь с выводом проекта моей библиотеки "crash", затем я добавил следующее событие после сборки, чтобы получить отчет после сборки:

"$(TargetDir)\$(TargetName).exe" --result_code=no --report_level=short

Вывод после сборки выглядит следующим образом:

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

Я ожидал, что тест EncoderAvailable завершится неудачей, поскольку я не инициализировал квартиру COM для потока. Я бы предположил, что я не могу использовать автоматические тесты, и вместо этого мне нужно заменить автоматические тесты на тесты, которые я сам определяю в основной функции и выполняю свои вызовы 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;
}

Вот выход сборки:

    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 ==========

Этот тест не пройден в первом тесте LameEncoderAvailable, который представляет собой следующую простую функцию:

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 () - я не думаю, что я должен делать это один раз за тест - это должно быть сделано только один раз для потока ...

Что касается тестирования exe-проектов, я думаю, вы могли бы указать отдельный main.cpp (testmain.cpp или что-то еще) и исключить ваш настоящий main.cpp из сборки для доступа к вашему коду. Если кто-нибудь знает более изящное решение для этого, я был бы рад услышать об этом ...

Ответы [ 4 ]

2 голосов
/ 07 марта 2011

Используйте Global Fixture . Светильники - отличный способ настроить код инициализации / завершения для каждого теста. Глобальное приспособление позволяет вам определить код инициализации / завершения для всего набора тестов.

0 голосов
/ 09 марта 2011

Вам НЕ нужно использовать init_unit_test_suite, поскольку эта функция выполняется перед выполнением любого из тестов.

Вы хотите использовать Global fixture. Вызов CoInitializeEx (NULL, COINIT_MULTITHREADED); в конструкторе и CoUnInitializeEx (); в деструкторе

0 голосов
/ 07 марта 2011

Почему бы не сделать CoInitialize, CoUnitialize для каждого теста?

Последующие вызовы CoInitialize или CoInitializeEx в том же потоке будут успешными, если они не попытаются изменить модель параллелизма, но будутreturn S_FALSE.

РЕДАКТИРОВАТЬ:

Предполагая, что тесты действительно выполняются одновременно.Один из способов сделать это - создать контейнер thread_specific, содержащий объект RAII CoInitialize / CoUnitialize.

0 голосов
/ 07 марта 2011

Не проверено, но поможет ли глобальная переменная, которая вызывает CoInitializeEx () в конструкторе?

...