Visual Studio - ATL COM 개체를 단위 테스트 하는 방법
ATL COM DLL의 경우, 직접 COM 객체를 CoCreateInstance로 생성하는 것도 가능하지만 소스 코드를 단위 테스트 프로젝트에 추가하는 방법도 고려해 볼 수 있습니다. (이런 경우, Code Coverage 수치는 안 나옵니다.)
예를 들어, "TestComObject"라는 ATL COM 개체를 만들었다면 다음과 같이 해당 Header 파일을 include하고 소스 코드를 포함시킨 다음, CComObject로 생성할 수 있습니다.
#include "stdafx.h"
#include "CppUnitTest.h"
#include "..\..\dllmain.h"
#include "..\..\TestComObject.h"
using namespace Microsoft::VisualStudio::CppUnitTestFramework;
namespace CppNativeTest
{
TEST_CLASS(Test_TestComObject)
{
public:
TEST_METHOD(Test_TestComObject_Initialize)
{
CComObject<CTestComObject> *inst;
HRESULT hRes = CComObject<CTestComObject>::CreateInstance(&inst);
}
};
}
CComObject를 사용하는 이유는, ATL COM Class의 경우 추상 함수를 포함하고 있기 때문입니다. 그런데, 이렇게 해도 단위 테스트를 실행하면 다음과 같은 오류가 발생합니다.
Test Name: Test_TestComObject_Initialize
Test FullName: CppNativeTest::Test_TestComObject::Test_TestComObject_Initialize
Test Source: d:\unittest\cppnativetest\TestComObjecttest.cpp : line 13
Test Outcome: Failed
Test Duration: 0:00:00.1421573
Result StackTrace:
at ATL::CComObject<CTestComObject>::CComObject<CTestComObject>() in c:\program files (x86)\microsoft visual studio 14.0\vc\atlmfc\include\atlcom.h:line 2908
at ATL::CComObject<CTestComObject>::CreateInstance() in c:\program files (x86)\microsoft visual studio 14.0\vc\atlmfc\include\atlcom.h:line 2966
at CppNativeTest::Test_TestComObject::Test_TestComObject_Initialize() in d:\unittest\cppnativetest\TestComObjecttest.cpp:line 17
Result Message: Exception Code: C0000005
문제가 발생한 atlcom.h의 소스 코드를 확인해 보면 _pAtlModule 포인터 값이 nullptr임을 알 수 있습니다.
// ===== atlcom.h
// ...[생략]...
template <class Base>
class CComObject :
public Base
{
public:
typedef Base _BaseClass;
CComObject(_In_opt_ void* = NULL)
{
_pAtlModule->Lock();
}
// ...[생략]...
}
// ...[생략]...
이 문제를 해결하려면 역시 ATL COM 프로젝트에 있던 Module 클래스를 맞춰주면 됩니다.
#include "..\..\TestComObject\dllmain.h"
TEST_METHOD(Test_TestComObject_Initialize)
{
CTestComObjectModule _AtlModule;
_pAtlModule = &_AtlModule;
CComObject<CTestComObject> *inst;
HRESULT hRes = CComObject<CTestComObject>::CreateInstance(&inst);
}
이렇게 바꾸고 컴파일하면 이번엔 빌드 오류가 나는데요.
Error LNK2001 unresolved external symbol LIBID_TestComObjectLib
이 값은 [...]_i.c 파일을 단위 테스트 프로젝트에 include 시켜주면 됩니다.
#include "..\..\TestComObject\TestComObject_i.c"
이외에도 단위 테스트 용도의 export 함수들을 ATL DLL에 포함시킨 다음 그것을 통해 COM 클래스를 호출하는 식으로도 고려해 볼 수 있습니다. 이런 경우 Code Coverage까지 모두 계산되어 좋습니다. 대신 출시 버전에 단위 테스트 함수들이 DLL에 포함되어 있는 것은 좋지 않기 때문에 Debug 빌드에만 적용하는 식이어야 할 것입니다.
[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]