2020년 6월 15일 월요일

Capter2( const, 실행중인 프로그램의 메모리 구조, 참조자, 참조자와 함수)


  • 키워드 Const
    • const int num = 10;   -> 변수 num을 상수화한다.
    • const int* ptr1 = &val1;  -> ptr1을 통해서 val1의 값을 수정하지 못한다.
    • int* const ptr2 = &val2;  -> ptr2는 상수화 된다. 따라서 val2의 주소외 다른 주소를 못가진다.
    • const int* const ptr3 = &val3;  -> ptr3는 상수화 되고, ptr3을 통해 val3의 값을 수정하지 못한다.

  • 실행중인 프로그램의 메모리 구조
    • 코드 영역 : 메모리의 코드영역은 실행할 프로그램의 코드가 저장되는 영역으로 텍스트영역이라고도 부른다. CPU는 코드영역에 저장된 명령어를 하나씩 가져와 처리하게된다.
    • 데이터 영역 : 프로그램의 전역 변수와 정적(static)변수가 저장되는 영역이다. 데이터 영역은 프로그램의 시작과 함께 할당되며, 프로그램 종료시 소멸된다.
    • 스택 영역 : 함수의 호출과 관계되는 지역변수와 매개변수가 저장되는 영역이다. 스택영역은 함수의 호출과 함께 할당되며, 함수호출이 완료되면 소멸한다. 이렇게 스택영역에 저장되는 함수의 호출정보를 스택프레임 이라고 한다. 스택은 푸시동작으로 데이터를 저장하고 팝동작으로 데이터를 인출한다. 가장 늦게 저정된 데이터가 가장 먼저 인출되는 구조이며, 메모리의 높은 주소에서 낮은 주소의 방향으로 할당된다.
      • 스택 프레임 : 함수가호출되면 스택에는 함수의 매개변수, 호출이 끝나고 돌아갈 반환 주소값, 함수의 선언된 지역변수 등이 저장된다. 이렇게 스택영역에 차례대로 저장되는 함수의 호출 정보를 스택프레임 이라고 한다. 스택프레임으로 인해 해당 함수가 함수의 일을 마친뒤 이전 상태로 돌아갈수 있는것이다.

    • 힙 형역 : 사용자가 관리할 수 있는 메모리 영역이다. 사용자에 의해 메모리를 동적으로 할당하고 해제하며 메모리의 낮은 주소에서 높은 주소의 방향으로 할당된다.
  • 참조자(Renference) : 할당된 하나의 메모리 공간에 둘 이상의 이름을 부여하는것으로 &연사자를 이용한다.  &연산자는 변수의 주소를 반환하는 연산자 이지만 변수 선언시 사용하게 되면 참조자의 선언이 된다. (ex int &num2 = num1; ) 
    • 참조자는 별칭이다.
    • 참조자의 수에는 제한이 없으며, 참조자를 대상으로도 참조자를 선언할수 있다.
  • 참조자와 함수 : C언어에서 Call-by-reference는 포인터를 이용하여 변수의 값을 수정하였다. 하지만 C++에서는 참조자를 이용하여 Call-by-reference구현할수 있다. 아래 구현 내용을 참고한다. 


2020년 6월 14일 일요일

Chap1(함수오버로딩, 매개변수 디폴트, 인라인 함수, 이름공간)

  • 함수 오버로딩 : 함수의 이름은 동일하지만 매개변수의 개수와 자료형이 다른경우 별개의 함수로 구분하는것. (C언어에서는 함수 이름만을 이용하여 호출대상을 찾기때무에 오버로딩을 허용하지 않지만 C++에서는 함수이름과 매개변수 선언을 보고 호출대상을 찾는다)
Ex>


  • 매개변수 디폴트 : 함수의 매개변수값을 기본으로 지정하여, 함수 호출시 매개변수의 인자값이 없을경우 지정된 값으로 설정된다. 주의  함수 선언부에서 설정해야한다. 
Ex>


  • 매크로함수 장/단점
    • 장점 
    1. 일반 함수보다 매크로함수의 실행 속도가 빠르다. 이유는 일반 함수의 경우 함수호출이 일어나면 매개변수나 호출자의 주소를 스택에 저장하는 행위를 하는 반면 매크로함수의 경우 전처리기에서 호출자를 치환해주기때문에 스택에 저장하는 등의 행위를 피할수 있다.
    2. 자료형에 의존적이지 않다. 
    • 단점 
    1. 매크로 함수의 경우 크기가 증가할 수록 괄호를 많이 써야하기때문에 가독성이 떨어진다.
    2. 디버깅이 어렵다.
  • 인라인(inline)함수 
    • 인라인을 직역하면 프로그램 코드라인 안으로 들어가버린 함수
    • 인라인함수는 매크로와 동일한 일을 한다. 단 일반 함수처럼 정의가 가능하다.
    • 매크로 함수는 전처리기에서 처리가 되지만 인라인함수는 컴파일 단계에서 컴파일러에 의해 처리되기때문에 인라인화가 성능에 해가된다고 컴파일러가 판단되면 컴파일러는 인라인 키워드를 무시하기도 하고, 일반 함수가 인라인화하여 성능향상에 도움이 된다고 판단하면 일반 함수로 인라인화 시키지 않아도 컴파일러에 의해 인라인 함수로 취급된다.


  • 이름공간(namespace)
    • 등장배경 : 예를 들어 은행관리 시스템 관리 프로그램을 만드는데 3개의 회사가 참여하였고 프로젝트 규모가 커서 일을 구분하여 독립적으로 진행하기로 했다고 가정하자. 3개의 회사는 각 각 개발을 완료하였고 3개의 회사가 모여 하나의 프로젝트를 완성하는 단계에서 함수의 이름이 동일하여 컴파일 문제가 발생하게 되었다. 이는 협업 과정에서 모든 함수의 이름을 만들때 규칙이 없었기 때문일 수도 있지만 이런 문제가 발생하게 되었을대 이름공간이 문제를 해결할 수 있다.
    • 사용방법은 아래 코드를 참고한다. 
    • 참고로 동일한 이름공간의 함수들은 이름공간의 명시 없이 사용가능하다.


    • 이름공간의 중첩 : 이름공간은 다른 이름공간 안에 삽입될수있다. 


    • using을 이용한 이름공간 명시 : 키워드 using을 이용하면 이름공간을 지정하지 않고도 함수를 호출할 수 있다. 아래 코드에서 main()함수의 using의 선언한 HybFunc()은 함수, 변수 모두 선언이 가능하다. 단, 지역변수 선언과 마찬가지로 지역을 벗어나면 그 효력을 읽게 된다.


    • 이름공간의 별칭 지정 : 이름공간의 중첩과 같이 여러개의 중첩이 일어난 경우 이름에 별칭을 부여할수도 있다.(개인적으로 이건 좀.... 아닌거같다)


    • 범위지정 연산자의 또다른 기능 : 지역변수의 이름과 전역변수의 이름이 동일한 경우 전역변수는 지역변수에 의해 가려지게 된다. 이런경우 전역변수를 사용할수 있게 해주는것이 범위지정 연산자 이다. 


2020년 6월 4일 목요일

이클립스 + Doxygen 연동

Doxygen은 소스파일에서 문서를 생성하는 컴파일러입니다.
Doxygen과 함께 사용하는 패키지로 Graphviz와 Mscgen을 많이 사용하는데, Graphviz는 다이어그램과 그래프를 그리는 패키지 이며 적극 권장합니다. 또한 Mscgen는 Graphviz와 유사하지만 메시지 시퀀스 다이어그램에 더 단순하고 최적화 되었습니다. Mscgen는 선택사항입니다.

다운로드 경로 :
Doxygen : https://anb0s.github.io/eclox/
Graphviz : http://www.graphviz.org
Mscgen : http://www.mcternan.me.uk/mscgen/


  1. 이클립스 + Doxygen 연동
    1. Doxygen을 다운로드 받고 압축을 해지한다.
    2. 이클립스 실행후 도움말 -> Install New Software -> 압축 해지한 Doxygen 폴더 추가 
    3. Eclox Doxygen, Eclox0.11 을 선택하고 다음 진행
    4. 설치가 완료
  2. 이클립스 doxygen 설정
    1. 아래 그림과 같이 설정





2020년 5월 26일 화요일

Doxygen 사용법

1. 기본적인 주석 형태
/**
* 기본적인 주석 형태
*/

2. 메인 페이지의 주석 
/**
* @mainpage 메인페이지의 제목을 적는다.
* @brief 간단한 설명
* @details 자세한 설명
* @section intro 소개
* @section Program 프로그램명
* @section INOUTPUT 입출력자료
* @section CREATEINFO 작성정보
* @section MODIFYINFO 수정 정보
*/

3. 각 파일에 들어갈 주석
/**
* @file hello.c
* @brief 간단한 설명
* @detail 자세한 설명
* @date 2018/1/30
*/

4. 각 함수에 대한 주석
/**
* @brief 어떤 기능을 하는 함수
* @param value 연산에 필요한 변수
* @return value 연산 결과를 반환
*/ 

5. 코드 삽입시 
@code
여기에 코드가 들어가면 된다.
@endcode

6. 버그 및 해야할 일 기록
@todo 언제까지 해야할일
@bug 값의 범위를 넘을경우 발생되는 버그가 있을 수 있다.

7. struct(class), enum
 /**  @brief buffer structor   Telnet에서 정송되는 데이터에 대해 프로토콜을 처리해야 하기 위하여,  효율적으로 데이터를 전송해야 할 입출력 버퍼 structor */ 
struct buffer{
  char *buf;   /**< 데이터를 저장할 주소공간   */         
  int size;   /**< buf에 할당된 메모리 크기   */         
  int head;   /**< buf에 저장된 데이터의 처음 Index   */
  int tail;   /**< buf에 저장된 데이터의 마지막 index */
  int count;  /**< buf에 저장된 데이터의 byte 수      */ 
}; 
 /** @brief TRUE FALSE정의. */ 
enum BOOLEAN { FALSE=0/**< FALSE */    TRUE /**< TRUE */ };

8. define, 전역 변수
#define MAX_READ_BUF   1024    /**< 최대 read buffer size      */
 short  port;                   /**< Telnet port number */ 


2020년 5월 16일 토요일

이클릅스 깃 연동

1. git서버에  폴더를 생성하고 git 초기화 해준다.
    $git init  --bare --shared

2. eclipse에서 oop C++프로젝트를 생성한다.


3. eclipse 메뉴창에서 창 -> Perspective -> Perspective 열기 -> 기타 를 선택하고, Git선택 후 열기


4. Clone a Git repository 를 선택하면 git저장소 복제 화면이 나오고 아래와 같이 설정한뒤 다음을 클릭한다.


5. Branch Selection에서 master로 체크되어있으면 다음을 클릭한다. 프로젝트의 내용이 비어있을 경우 master가 표시 되지 않을수도 있다.

6.  Local Destination의 내용은 다음과 같다.
대상 디렉토리는 이클립스에서 git서버와 연동될 폴더 지정이다.

7. 다시 C++프로젝트 퍼스펙티브로 이동하여 oop프로젝트 에서 우측 클릭을 하면 팀이 나오고 팀에서 프로젝트 공유를 선택하여 아래와 같이 설정하고 완료 한다.
Repository에서 방금 생성한 git서버를 선택


2020년 4월 25일 토요일

GOOGLE TEST MANUAL (Primer)

ㄹGoogletest Primer

소개 : 왜 구글테스트인가?

구글테스트는 더 나은 C++테스트를 작성하는데 도움이 됩니다.
googletest는 Google의 특정 요구 사항과 제약 사항을 염두에두고 테스팅 기술 팀에서 개발 한 테스트 프레임 워크입니다. Linux, Windows, Mac 어디서든 C++ 코드를 작성하면 googletest가 도움이 될 수 있습니다. 또한 단위 테스트뿐만 아니라 모든 종류의 테스트를 지원합니다.


명명법에 주의 하라.

참고 : Test, Test Case 및 Test Suite라는 용어를 다르게 정의하면 약간의 혼동이있을 수 있으므로이를 오해하지 마십시오.

역사적으로 googletest는 관련 테스트를 그룹화하기 위해 테스트 케이스라는 용어를 사용하기 시작했지만 ISTQB (International Software Testing Qualifications Board) 자료 및 소프트웨어 품질에 대한 다양한 교재를 포함하여 현재 발행물은 이를 위해 Test Suite라는 용어를 사용합니다.

googletest에서 사용되는 테스트라는 용어는 ISTQB 및 기타 Test Case라는 용어에 해당합니다.

Test라는 용어는 ISTQB의 Test Case 정의를 포함하여 일반적으로 충분히 의미가 있으므로 여기서 큰 문제는 아닙니다. 그러나 Google 테스트에 사용 된 Test Cse라는 용어는 모순되는 의미이므로 혼동됩니다.

googletest는 최근 Test Case라는 용어를 Test Suite로 대체하기 시작했습니다. 선호하는 API는 TestSuite입니다. 이전 TestCase API는 천천히 사용이 중단되고 리팩터링됩니다

따라서 용어에 대한 다른 정의에 유의하십시오.

Assertions

googletest의 assertions은 함수 호출과 유사한 매크로입니다. 동작에 대해 assertions을 작성하여 클래스 또는 함수를 테스트합니다. assertions이 실패하면 googletest는 assertions의 소스 파일과 줄 번호 위치를 실패 메시지와 함께 인쇄합니다. googletest의 메시지에 추가 될 맞춤 실패 메시지를 제공 할 수도 있습니다.

assertions은 쌍을 이루어 동일한 것을 테스트하지만 현재 기능에 다른 영향을 미칩니다. 따라서
ASSERT_*은 실패하면 치명적 실패를 생성하고 현재 기능을 중단합니다.
EXPECT_*은 치명적이지 않은 오류를 생성하여 현재 기능을 중단시키지 않습니다. 일반적으로 EXPECT_* 는 테스트에서 둘 이상의 실패를보고 할 수 있으므로 선호됩니다. 그러나 해당 assertions이 실패 할 때 계속하는 것이 타당하지 않은 경우 ASSERT_ *를 사용해야합니다.

실패한 ASSERT_*는 현재 함수에서 즉시 리턴하므로 그 뒤에 오는 clean-up코드를 건너 뛸 수 있으므로 space leak(or memory leak)이 발생할 수 있습니다. 누출의 특성에 따라 수정해야 할 수도 있고 그렇지 않을 수도 있습니다. 따라서 어설 션 오류 외에 힙 검사기 오류가 발생하면이 점을 명심하십시오.

사용자 정의 실패 메시지를 제공하려면 << 연산자를 사용하여 매크로에 간단히 메시지를 스트리밍하십시오. 예를 들면 :
ASSERT_EQ(x.size(), y.size()) << "Vectors x and y are of unequal length";

for (int i = 0; i &lt; x.size(); ++i) {
  EXPECT_EQ(x[i], y[i]) << "Vectors x and y differ at index " &lt;&lt; i;
}

Basic Assertions

이러한 assertions은 참/거짓 조건 테스트를 수행합니다.
Fatal assertionNonfatal assertionVerifies
ASSERT_TRUE(condition);EXPECT_TRUE(condition);condition is true
ASSERT_FALSE(condition);EXPECT_FALSE(condition);condition is false
실패하면 ASSERT_ *는 치명적 실패를 생성하고 현재 함수에서 리턴하며 EXPECT_ *는 치명적이지 않은 실패를 생성하여 함수를 계속 실행할 수 있습니다. 두 경우 모두 assertions 오류는 테스트에 실패했음을 의미합니다.

Binary Comparison

이 섹션에서는 두 값을 비교하는 assertions에 대해 설명합니다.
Fatal assertionNonfatal assertionVerifies
ASSERT_EQ(val1, val2);EXPECT_EQ(val1, val2);val1 == val2
ASSERT_NE(val1, val2);EXPECT_NE(val1, val2);val1 != val2
ASSERT_LT(val1, val2);EXPECT_LT(val1, val2);val1 &lt; val2
ASSERT_LE(val1, val2);EXPECT_LE(val1, val2);val1 &lt;= val2
ASSERT_GT(val1, val2);EXPECT_GT(val1, val2);val1 &gt; val2
ASSERT_GE(val1, val2);EXPECT_GE(val1, val2);val1 &gt;= val2
값 인수(val1, val2)는 assertions의 비교 연산자와 비교할 수 있어야합니다. 그렇지 않으면 컴파일러 오류가 발생합니다.  <<가 지원되면 어설 션이 실패 할 때 인수를 인쇄하기 위해 호출됩니다. 그렇지 않으면 googletest는 최선의 방법으로 인쇄하려고 시도합니다. 자세한 내용과 인수 인쇄를 사용자 정의하는 방법은 설명서를 참조하십시오.

이러한 assertions은 사용자 정의 형식에서 작동하지만 해당 비교 연산자 (예 : == 또는 <)를 정의한 경우에만 작동합니다. Google C++ 스타일 가이드에서는 권장하지 않으므로 ASSERT_TRUE() 또는 EXPECT_TRUE()를 사용하여 사용자 정의 유형의 두 객체가 동일한 지 확인해야합니다.
그러나 ASSERT_EQ (실제, 예상)가 ASSERT_TRUE (실제 == 예상)보다 선호됩니다. 실패시 실제 및 예상 값을 알려줍니다.

인수는 항상 정확히 한 번만 평가됩니다. 따라서 인수에 side effects를 가진것도 좋습니다. 그러나 일반적인 C/C++ 함수와 마찬가지로 인수의 평가 순서는 정의되어 있지 않으며 (즉, 컴파일러는 순서를 자유롭게 선택할 수 있습니다) 코드는 특정 인수 평가 순서에 의존해서는 안됩니다.

ASSERT_EQ()는 포인터에서 포인터 동등성을 수행합니다. 두 개의 C 문자열에서 사용되는 경우 동일한 값이 아닌 동일한 메모리 위치에 있는지 테스트합니다. 따라서 C 문자열 (예 : const char *)을 값으로 비교하려면 나중에 설명 할 ASSERT_STREQ()를 사용하십시오. 특히 C 문자열이 NULL임을 확인하려면 ASSERT_STREQ(c_string, NULL)를 사용하십시오. c ++ 11이 지원되는 경우 ASSERT_EQ(c_string, nullptr)를 사용하십시오. 두 개의 문자열 객체를 비교하려면 ASSERT_EQ를 사용해야합니다.

포인터 비교를 수행 할 때 *_EQ(ptr, NULL) 및 *_NE(ptr, NULL) 대신 *_EQ(ptr, nullptr) 및 *_NE(ptr, nullptr)을 사용하십시오.자세한 내용은 FAQ를 참조하십시오.

부동 소수점 숫자로 작업하는 경우 반올림으로 인한 문제를 피하기 위해 이러한 매크로 중 일부의 부동 소수점 변형을 사용할 수 있습니다. 자세한 내용은 고급 googletest 주제를 참조하십시오.

String Comparison

이 그룹의 assertions은 두 개의 C문자열을 비교합니다. 두 개의 문자열 객체를 비교하려면 EXPECT_EQ, EXPECT_NE 등을 대신 사용하십시오.
Fatal assertionNonfatal assertionVerifies
ASSERT_STREQ(str1,str2);EXPECT_STREQ(str1,str2);두 문자열의 내용이 동일합니다
ASSERT_STRNE(str1,str2);EXPECT_STRNE(str1,str2);두 문자열의 내용이 다릅니다
ASSERT_STRCASEEQ(str1,str2);EXPECT_STRCASEEQ(str1,str2);두 문자열은 대/소 문자를 무시하고 내용이 동일합니다.
ASSERT_STRCASENE(str1,str2);EXPECT_STRCASENE(str1,str2);두 문자열은 대소 문자를 무시하고 내용이 다릅니다.

Simple Tests

테스트를 만들려면

1. 테스트 함수를 정의하고 이름을 지정하려면 TEST() 매크로를 사용하십시오. 이들은 값을 반환하지 않는 일반적인 C++ 함수입니다.
2. 이 함수에서 포함하려는 유효한 C++ 문과 함께 다양한 googletest 어설 션을 사용하여 값을 확인하십시오.
3. 테스트 결과는 assertions에 의해 결정됩니다. 테스트에서 어설 션이 치명적이거나 치명적이지 않은 경우 또는 테스트가 중단되면 전체 테스트가 실패합니다. 그렇지 않으면 성공합니다.
TEST(TestSuiteName, TestName) {
  ... test body ...
}
TEST() 인수는 일반에서 구체적으로 진행됩니다. 첫 번째 인수는 test suite의 이름이고 두 번째 인수는 test suite내의 테스트 이름입니다. 두 이름 모두 유효한 C++ 식별자 여야하며 밑줄 (_)을 포함해서는 안됩니다. 테스트의 전체 이름은 포함된 test suite와 개별 이름으로 구성됩니다. 다른 테스트 test suite의 테스트는 동일한 개별 이름을 가질 수 있습니다.

예를 들어 간단한 정수 함수를 보자.
int Factorial(int n);  // Returns the factorial of n
이 함수의 test suite는 다음과 같습니다.
// Tests factorial of 0.
TEST(FactorialTest, HandlesZeroInput) {
  EXPECT_EQ(Factorial(0), 1);
}

// Tests factorial of positive numbers.
TEST(FactorialTest, HandlesPositiveInput) {
  EXPECT_EQ(Factorial(1), 1);
  EXPECT_EQ(Factorial(2), 2);
  EXPECT_EQ(Factorial(3), 6);
  EXPECT_EQ(Factorial(8), 40320);
}
googletest는 테스트 결과를 test suite별로 그룹화하므로 논리적으로 관련된 테스트는 동일한 test suite에 있어야합니다. 다시 말해, TEST()에 대한 첫 번째 인수는 동일해야합니다. 위의 예에서, 동일한 test suite인 FactorialTest에 속하는 두 개의 테스트 (HandlesZeroInput 및 HandlesPositiveInput)가 있습니다.

테스트 test suite이름을 지정할 때는 함수 및 클래스 이름 지정과 동일한 규칙을 따라야합니다.

Test Fixtures: Using the Same Data Configuration for Multiple Tests {#same-data-multiple-tests}

비슷한 데이터에서 작동하는 둘 이상의 테스트를 작성하는 경우 테스트 픽스처를 사용할 수 있습니다. 이를 통해 여러 가지 다른 테스트에 동일한 구성의 객체를 재사용 할 수 있습니다.

fixture을 만들려면 :

1. :: testing :: Test에서 클래스를 파생시킵니다. 서브 클래스에서 fixture 멤버에 접근하고 싶기 때문에 protected :로 본문을 시작하십시오.
2. 클래스 내에서 사용할 객체를 선언하십시오.
3. 필요한 경우 기본 생성자 또는 SetUp() 함수를 작성하여 각 테스트에 대한 개체를 준비하십시오. 일반적인 실수는 C++ 11에서 대문자 U를 소문자 u로 재정의 하여 SetUp()을 Setup()으로 사용하는 것 입니다. 철자가 올바른지 확인하세요. 
4. 필요한 경우, 소멸자 또는 TearDown() 함수를 작성하여 SetUp()에 할당 한 모든 리소스를 해제하십시오. 생성자/소멸자를 사용해야 할 때와 SetUp()/TearDown()을 사용해야 할 때를 알려면 FAQ를 읽으십시오.
5. 필요한 경우 테스트에서 공유 할 서브 루틴을 정의하십시오.
TEST_F(TestFixtureName, TestName) {
  ... test body ...
}
TEST()와 마찬가지로 첫 번째 인수는 test suite이름이지만 TEST_F()의 경우 test fixture클래스의 이름이어야합니다. 당신은 아마 추측했을 것입니다 : _F는 Fixture입니다.

불행히도 C++ 매크로 시스템은 두 가지 유형의 테스트를 모두 처리 할 수있는 단일 매크로를 만들 수 없습니다. 잘못된 매크로를 사용하면 컴파일러 오류가 발생합니다.

또한 test fixture클래스를 TEST_F()에서 사용하기 전에 먼저 정의해야합니다. 그렇지 않으면 컴파일러 오류 "virtual outside class declaration"이 발생합니다.

TEST_F()로 정의 된 각 테스트에 대해 googletest는 런타임시 새로운 테스트 설비를 생성하고 즉시 SetUp()을 통해 초기화하고 테스트를 실행 한 다음 TearDown()을 호출하여 정리 한 다음 테스트 설비를 삭제합니다. 동일한 test suite의 테스트마다 test fixture객체가 다르므로 googletest는 다음 test fixture를 작성하기 전에 항상 test fixture를 삭제합니다. googletest는 여러 테스트에 동일한 test fixture를 재사용하지 않습니다. 한 번의 테스트로 texture를 변경해도 다른 테스트에는 영향을 미치지 않습니다.

예를 들어, 다음 인터페이스가있는 Queue라는 FIFO 대기열 클래스에 대한 테스트를 작성해 보겠습니다.
template <typename E>  // E is the element type.
class Queue {
 public:
  Queue();
  void Enqueue(const E& element);
  E* Dequeue();  // Returns NULL if the queue is empty.
  size_t size() const;
  ...
};
먼저 fixture클래스를 정의하십시오. 규칙에 따라 FooTest라는 이름을 지정해야합니다. 여기서 Foo는 테스트중인 클래스입니다.
class QueueTest : public ::testing::Test {
 protected:
  void SetUp() override {
     q1_.Enqueue(1);
     q2_.Enqueue(2);
     q2_.Enqueue(3);
  }

  // void TearDown() override {}

  Queue<int> q0_;
  Queue<int> q1_;
  Queue<int> q2_;
};
이 경우 소멸자가 이미 수행 한 것 이외의 각 테스트 후에 정리할 필요가 없으므로 TearDown()이 필요하지 않습니다.

이제 TEST_F ()와이 조명기를 사용하여 테스트를 작성합니다.
TEST_F(QueueTest, IsEmptyInitially) {
  EXPECT_EQ(q0_.size(), 0);
}

TEST_F(QueueTest, DequeueWorks) {
  int* n = q0_.Dequeue();
  EXPECT_EQ(n, nullptr);

  n = q1_.Dequeue();
  ASSERT_NE(n, nullptr);
  EXPECT_EQ(*n, 1);
  EXPECT_EQ(q1_.size(), 0);
  delete n;

  n = q2_.Dequeue();
  ASSERT_NE(n, nullptr);
  EXPECT_EQ(*n, 2);
  EXPECT_EQ(q2_.size(), 1);
  delete n;
}
위의 ASSERT_* 및 EXPECT_* 어설 션을 모두 사용합니다. 경험적으로 어설 션 오류 후에 테스트에서 더 많은 오류를 계속 나타내려면 EXPECT_*를 사용하고 실패 후 계속할 때는 ASSERT_*를 사용하는 것이 좋습니다. 예를 들어, Dequeue 테스트에서 두 번째 어설 션은 ASSERT_NE(nullptr, n)입니다. 나중에 포인터 n을 역 참조해야하므로 n이 NULL 일 때 segfault가 발생합니다.

이러한 테스트가 실행되면 다음이 발생합니다.
1. googletest는 QueueTest 객체를 생성합니다 (t1이라고 함).
2. t1.SetUp ()은 t1을 초기화합니다.
3. 첫 번째 테스트 (IsEmptyInitially)는 t1에서 실행됩니다.
4. 테스트가 완료된 후 t1.TearDown ()이 정리됩니다.
5. t1이 파괴되었습니다.
6. 위의 단계는 다른 QueueTest 객체에서 반복되며 이번에는 DequeueWorks 테스트를 실행합니다.

테스트 호출

TEST() 및 TEST_F()는 테스트를 googletest에 암시 적으로 등록합니다. 따라서 다른 많은 C++ 테스트 프레임 워크와 달리 정의 된 테스트를 모두 실행하기 위해 다시 나열 할 필요는 없습니다.

테스트를 정의한 후 RUN_ALL_TESTS()로 테스트를 실행할 수 있습니다. 모든 테스트가 성공하면 0을, 그렇지 않으면 1을 리턴합니다. RUN_ALL_TESTS ()는 링크 단위에서 모든 테스트를 실행합니다. 테스트 단위 나 소스 파일이 다를 수 있습니다.

호출되면 RUN_ALL_TESTS()매크로는 다음과 같습니다.

  • 모든 googletest 플래그의 상태를 저장합니다.
  • 첫 번째 테스트에 대한 테스트 픽스처 객체를 만듭니다.
  • SetUp ()을 통해 초기화합니다.
  • fixture 객체에서 테스트를 실행합니다.
  • TearDown ()을 통해 조명기를 정리합니다.
  • fixture를 삭제합니다.
  • 모든 googletest 플래그의 상태를 복원합니다.
  • 모든 테스트가 실행될 때까지 다음 테스트에 대해 위 단계를 반복합니다.
치명적인 오류가 발생하면 후속 단계를 건너 뜁니다.
중요 : RUN_ALL_TESTS()의 반환 값을 무시해서는 안됩니다. 그렇지 않으면 컴파일러 오류가 발생합니다. 이 설계의 근거는 자동화 된 테스트 서비스가 stdout/stderr 출력이 아니라 종료 코드를 기반으로 테스트가 통과했는지 여부를 결정한다는 것입니다. 따라서 main() 함수는 RUN_ALL_TESTS()의 값을 반환해야합니다.

또한 RUN_ALL_TESTS()를 한 번만 호출해야합니다. 그것을 두 번 이상 호출하면 일부 고급 Google 테스트 기능 (예 : 스레드 안전 사망 테스트)과 충돌하므로 지원되지 않습니다.

Writing the main() Function

대부분의 사용자는 고유한 기본 기능을 작성할 필요가 없으며 대신 적절한 진입 점을 정의하는 gtest_main(gtest와 반대로)과 연결해야합니다. 자세한 내용은이 섹션의 끝 부분을 참조하십시오. 이 섹션의 나머지 부분은 테스트를 실행하기 전에 fixture 및test suites의 프레임 워크 내에서 표현할 수없는 사용자 정의 작업을 수행해야하는 경우에만 적용해야합니다.

자체 main() 함수를 작성하면 RUN_ALL_TESTS() 값을 리턴해야합니다.

이 상용구에서 시작할 수 있습니다 :
#include "this/package/foo.h"

#include "gtest/gtest.h"

namespace my {
namespace project {
namespace {

// The fixture for testing class Foo.
class FooTest : public ::testing::Test {
 protected:
  // You can remove any or all of the following functions if their bodies would
  // be empty.

  FooTest() {
     // You can do set-up work for each test here.
  }

  ~FooTest() override {
     // You can do clean-up work that doesn't throw exceptions here.
  }

  // If the constructor and destructor are not enough for setting up
  // and cleaning up each test, you can define the following methods:

  void SetUp() override {
     // Code here will be called immediately after the constructor (right
     // before each test).
  }

  void TearDown() override {
     // Code here will be called immediately after each test (right
     // before the destructor).
  }

  // Class members declared here can be used by all tests in the test suite
  // for Foo.
};

// Tests that the Foo::Bar() method does Abc.
TEST_F(FooTest, MethodBarDoesAbc) {
  const std::string input_filepath = "this/package/testdata/myinputfile.dat";
  const std::string output_filepath = "this/package/testdata/myoutputfile.dat";
  Foo f;
  EXPECT_EQ(f.Bar(input_filepath, output_filepath), 0);
}

// Tests that Foo does Xyz.
TEST_F(FooTest, DoesXyz) {
  // Exercises the Xyz feature of Foo.
}

}  // namespace
}  // namespace project
}  // namespace my

int main(int argc, char **argv) {
  ::testing::InitGoogleTest(&argc, argv);
  return RUN_ALL_TESTS();
}

:: testing :: InitGoogleTest() 함수는 googletest 플래그에 대한 명령 행을 구문 분석하고 인식 된 모든 플래그를 제거합니다. 이를 통해 사용자는 AdvancedGuide에서 다룰 다양한 플래그를 통해 테스트 프로그램의 동작을 제어 할 수 있습니다. RUN_ALL_TESTS()를 호출하기 전에 이 함수를 호출해야합니다. 그렇지 않으면 플래그가 제대로 초기화되지 않습니다.

Windows에서는 InitGoogleTest()도 넓은 문자열과 함께 작동하므로 UNICODE 모드로 컴파일 된 프로그램에서도 사용할 수 있습니다.

그러나 모든 주요 기능을 작성하는 것이 너무 많은 일이라고 생각하십니까? 우리는 전적으로 귀하에게 동의하며, 이것이 Google 테스트가 main()의 기본 구현을 제공하는 이유입니다. 요구 사항에 맞는 경우 테스트를 gtest_main 라이브러리와 연결하면 좋습니다.

참고 : ParseGUnitFlags ()는 InitGoogleTest()를 위해 더 이상 사용되지 않습니다.

알려진 제한

Google 테스트는 스레드 안전하도록 설계되었습니다. pthreads 라이브러리가 사용 가능한 시스템에서는 구현이 스레드로부터 안전합니다. 현재 다른 시스템 (예 : Windows)에서 두 스레드의 Google 테스트 어설 션을 동시에 사용하는 것은 안전하지 않습니다. 대부분의 테스트에서는 일반적으로 어설 션이 기본 스레드에서 수행되므로 문제가되지 않습니다. 도움이 필요한 경우 gtest-port.h에서 플랫폼에 필요한 동기화 프리미티브를 구현할 수 있습니다.







VITIS Git + Doxygen Config

 Doxygen Configure 1. Vitis 메뉴의 Window->Preference의 C/C++ -> Editor의 Documentation tool comments 기본 설정값을 Doxygen으로 변경 설정 후 함수 바로 위에서 /...