블로그 이미지

Recent Comment

Recent Trackback

Archive

calendar

    1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31    
  • 109,054total
  • 32today
  • 41yesterday
2009.10.30 08:30 Visual Studio


Visual Studio 2010 C++ Unit Test

Visual Studio 2008에서부터 단위테스트 IDE가 추가 되었습니다.

단위테스트 프로젝트를 추가하여 해당 모듈, 기능등이 정상적으로 동작하는지를 개발과 함께 진행 함으로써 SW품질 향상과 버그를 미리 방지할 수 있습니다.

이번 포스트에서는 Visual Studio 2010  단위테스트 구조와 함께 C++ 단위테스트방법에 대해 다룹니다.

 

Visual Studio 2010 Unit Test  구조

Visual Studio 2010에서 단위테스트 프로젝트를 생성하면 UnitTesting 네임스페이스와 TestClassAttribute, TestContext클래스를 사용합니다.

UnitTesting

Ø  Assert 클래스를 사용하여 단위테스트의 결과를 확인할 수 있습니다.

Ø  Initialization/Cleanup attribute로 단위테스트 전/후 실행 상태를 설정할 수 있습니다.

Ø  TestContext클래스로 data-driven 테스트나 ASP.NET 웹서비스의 단위테스트를 가능하게 합니다.

TestClassAttribute

단위테스트 프로젝트를 생성하면 [TestMethod] attribute가 생성되어 특정 테스트 메서드를 호출합니다. [TestMethod] attribute가 없으면 Test Suite에서 제외 됩니다.

TestContext

각 단위테스트의 결과 정보를 가지는 멤버변수로 가집니다.

 

아래 코드는 단위 테스트 프로젝트를 생성하면 생성되는 기본 클래스 구조입니다.

위에서 설명한 UnitTesting 네임스페이스를 사용하고, TestClassAttribute 클래스의 [TestClass] [TestMethod] attribute 를 설정하고, TestContext  인스턴스를 멤버 변수로 가지고 있는 것을 확인 할 수 있습니다. (C++ 단위 테스트 프로젝트를 생성 하였습니다.)

 

#include "stdafx.h"

 

using namespace System;

using namespace System::Text;

using namespace System::Collections::Generic;

using namespace        Microsoft::VisualStudio::TestTools::UnitTesting;

 

namespace BankAccountTestSuite

{

        [TestClass]

        public ref class UnitTest1

        {

        private:

               TestContext^ testContextInstance;

 

        public:

               /// <summary>

               ///Gets or sets the test context which provides

               ///information about and functionality for the current test run.

               ///</summary>

       

                      생략….

               #pragma endregion

 

               [TestMethod]

               void TestMethod1()

               {

                       //

                       // TODO: Add test logic       here

                       //

               };

        };

}

 

 
































C++ Unit Test 
예제

Visual Studio
에서 제공 되는 단위 테스트는 기본 적으로 .NET
기반으로 동작을 합니다.

그렇다고 네이티브 C++ 단위테스트를 못하는 것은 아닙니다.

이번 예제에서는 네이티브 C++클래스를 .NET reference Class 로 마샬링하여 단위테스트를 하는 방법을 설명 합니다.

먼저 C++ 프로젝트를 만듭니다.
단위테스트 할 개인 은행 창구 관리 클래스를 만듭니다.

//bankAccount.h

#pragma once

#include <iostream>

#include <string>

using namespace std;

 

class CBankAccount

{

public:

         CBankAccount(void);

         CBankAccount(const string& customerName, const double& balance);

 

         ~CBankAccount(void);

         bool InitAccount(const string& customerName, const double& balance)

         {

                  if(customerName.length() == 0)

                           return false;

                  m_customerName = customerName;

                  m_balance = balance;

                  m_frozen=false;

                  return true;

         }

         const string& GetCustomerName();

         const double& GetBalance();

         const bool& IsFrozen();

         void Debit(const double& amount);

         void Credit(const double& amount);

         void FreezeAccount();

         void UnFreezeAccount();

private:

         string m_customerName;

         double m_balance;

         bool m_frozen;

};

//bankAccount.cpp

#include "StdAfx.h"

#include "BankAccount.h"

 

 

CBankAccount::CBankAccount(void)

{

}

 

CBankAccount::CBankAccount(const string& customerName, const double& balance)

{

                  m_customerName= customerName;

                  m_balance = balance;

                  m_frozen = false;

}

 

CBankAccount::~CBankAccount(void)

{

}

 

const string& CBankAccount::GetCustomerName()

{

                  return m_customerName;

}

 

const double& CBankAccount::GetBalance()

{

                  return m_balance;

}

 

const bool& CBankAccount::IsFrozen()

{

                  return m_frozen;

}

 

void CBankAccount::Debit(const double& amount)

{

                  m_balance -= amount;

}

 

void CBankAccount::Credit(const double& amount)

{

                  m_balance += amount;

}

 

void CBankAccount::FreezeAccount()

{

                  m_frozen = true;

}

 

void CBankAccount::UnFreezeAccount()

{

                  m_frozen = false;

}

 

그리고 C++ 단위 테스트 프로젝트를 추가 합니다.

 

 

프로젝트를 추가하고 위에서 만든 BankAccount.h BankAccount.cpp 파일을 단위 테스트 프로젝트에 추가 합니다.

 

Visual Studio 에서 생성한 C++ 단위테스트 프로젝트는 C++/CLR 언어로 구현이 되어있습니다.

예제에서는 네이티브 C++ C++/CLR 프로젝트에서 사용하여야 하므로, 프로젝트 설정에서 Common Language Runtime SupportCommon Language Runtime Support(/clr)로 설정을 합니다. 

 


Ø  Managed 클래스에서 네이티브 C++클래스를 사용하기 위해 ref class Embedded 클래스를 추가 합니다.

Ø  Char* System::String으로 마샬링하는 함수 MarshalString 추가 합니다.

Ø   첫번째 단위 테스트 메서드, TestMethod1에서 은행 계좌 정보를 생성하는 CBankAccount::Initialize 함수를 호출합니다 


 

#include "stdafx.h"

#include "..\BankAccount.h"

#include <msclr\marshal.h>

using namespace System;

using namespace System::Text;

using namespace System::Collections::Generic;

using namespace        Microsoft::VisualStudio::TestTools::UnitTesting;

using namespace msclr::interop;

using namespace Runtime::InteropServices;

 

 

namespace MFCDlgTestSuite

{

 

        void MarshalString ( String ^ s, string& os )

        {

                const char* chars =

                (const char*)(Marshal::StringToHGlobalAnsi(s)).ToPointer();

               os = chars;

                Marshal::FreeHGlobal(IntPtr((void*)chars));

        }

 

 

        template<typename T>

        ref class Embedded

        {

               T* t;

               !Embedded()

               {

                       if( t != nullptr)

                       {

                              delete t;

                              t= nullptr;

                       }

               }

               ~Embedded()

               {

                       this->!Embedded();

               }

        public:

               Embedded() : t(new T)

               {

               }

               static T* operator& (Embedded% e)

               {

                       return e.t;

               }

               static T* operator-> (Embedded% e)

               {

                       return e.t;

               }

        };

 

        [TestClass]

        public ref class UnitTest1

        {

        private:

               TestContext^ testContextInstance;

 

        public:

               /// <summary>

               ///Gets or sets the test context which provides

               ///information about and functionality for the current test run.

               ///</summary>

            ///생략.

               #pragma endregion

 

               [TestMethod]

               void TestMethod1()

                {

                       //

                       // TODO: Add test logic       here

                       //

               };

        };

}

 

 

네이티브 코드와 CLR코드가 함께 잘 동작하는 환경을 구축하고 단위 테스트 코드를 추가 합니다.

단위 테스트는 먼저 CBankAccount::Initialize함수를 테스트하는 코드를 작성합니다.

테스트 코드를 작성하고 메뉴>>Test>>Run>>Tests in Current Context 메뉴를 선택하면 단위테스트가 실행이 됩니다.

 


아래 코드는 CBankAccount::Initialize함수 호출에 실패하는 코드와 성공하는 코드의 예입니다.

 

void TestMethod1()

{

        //

        // TODO: Add test logic       here

        //

         

        std::string stdAccName;

       //Account 이름이 NULL 주어 Initialize함수에서 false 리턴 하게 하여

//unit test에서 실패 하는 코드 .

       String^ clrAccName = gcnew String("");

       bool result;

       //Managed String Unmanaged string으로 변환

       MarshalString(clrAccName, stdAccName);

       Embedded<CBankAccount> BA;

       result = BA->InitAccount(stdAccName, 1000000.0 );

        System::Boolean clrBool = System::Convert::ToBoolean(result);

        Assert::IsFalse(clrBool);

        if(clrBool == false)

            Assert::Inconclusive("Initialize Fail");

};

void TestMethod1()

{

         //

         // TODO: Add test logic           here

         //

        //CBankAccount::Initialize 함수에 정상적인 파라메터를 주어 Unit Test
             //
 성공하는 코드

        std::string stdAccName;

        String^ clrAccName = gcnew String("Kim Ryungee");

        bool result;

        //Managed String Unmanaged string으로 변환

        MarshalString(clrAccName, stdAccName);

        Embedded<CBankAccount> BA;

        result = BA->InitAccount(stdAccName, 1000000.0 );

        System::Boolean clrBool = System::Convert::ToBoolean(result);

        Assert::IsFalse(clrBool);

        if(clrBool == false)

            Assert::Inconclusive("Initialize Fail");

};

 

 

 

 

 
참고 사이트 

http://msdn.microsoft.com/en-us/library/ms243401.aspx
http://msdn.microsoft.com/en-us/library/microsoft.visualstudio.testtools.unittesting.assert.equals.aspx
http://msdn.microsoft.com/en-us/library/ms235281(VS.80).aspx

신고
posted by 김연기

티스토리 툴바