C++ gmock

mohadang·2022년 8월 21일
0

C++

목록 보기
47/48
post-thumbnail
post-custom-banner

gmock 이란

  • googletest에서 제공하는 mock 객체
  • mock 객체는 테스트전 미리 동작이 정의 되어 테스트 실행시 정의된 동작을 수행한다.
  • 미리 동작을 정의하는 과정에서 호출 하려는 메소드, 메소드 호출 순서, 호출 횟수, 인자, 반환 값을 정의할 수 있다.
  • mock 객체는 stub(미리 정의된 값을 반환)이나 spy(미리 정의된 호출이 의도대로 호출 되는지 감지) 역할을 수행할 수 있다.

gmock 예제

  • 실제 객체
class Turtle {
  ...
  virtual void PenUp() = 0;
  virtual void PenDown() = 0;
  virtual void Forward(int distance) = 0;
  virtual void Turn(int degrees) = 0;
  virtual void GoTo(int x, int y) = 0;
  virtual int GetX() const = 0;
  virtual int GetY() const = 0;
};
  • mock 객체
#include "gmock/gmock.h"

class MockTurtle : public Turtle {
public:
  ...
  MOCK_METHOD(void, PenUp, (), (override));
  MOCK_METHOD(void, PenDown, (), (override));
  MOCK_METHOD(void, Forward, (int distance), (override));
  MOCK_METHOD(void, Turn, (int degrees), (override));
  MOCK_METHOD(void, GoTo, (int x, int y), (override));
  MOCK_METHOD(int, GetX, (), (const, override));
  MOCK_METHOD(int, GetY, (), (const, override));
};

gmock 클래스

class MyMock {
public:
  MOCK_METHOD(ReturnType, MethodName, (Args...));
  MOCK_METHOD(ReturnType, MethodName, (Args...), (Specs...));
};
  • MOCK_METHOD로 mock 객체의 메소드를 정의
  • 처음 3개의 인자들은 메소드 선언을 표현
  • 4번재 인자
    • 여러개의 인자가 리스트로 들어갈 수 있다.
    • const - const 메소드로 만듬. const 메소드를 overriding 할때 필요
    • override - 메소드를 override 할때 필요 virtual 메소드를 overriding 할때 필요.
    • noexcept - 메소드를 noexcept로 만듬. noexcept 메소드를 overriding 할때 필요.
    • Calltype(...) - 호출 타입 설정 (e.g. to STDMETHODCALLTYPE), 윈도우에서 유용.
    • ref(...) - 참조값 지정

mock 사용 흐름

#1 : gmock 이름을 testing 네임스페이스 포함
#2 : mock 객체 생성
#3 : 예상 동작 정의(이 메소드가 얼마나 호출 될 것인가? 어떤 인자와 함께? 어떤 동작을 할까? etc...).
#4 : 테스트 코드 실행, 부가적으로 결과값을 googletest assertions으로 확인. mock 객체의 메소드가 예상한것 보다 한번더 호출 되거나 예상하지 못한 인자로 메소드가 호출 되었는지 검사(실행중에 예상 동작과 다르게 동작하면 바로 테스트 실패)
#5 : mock 개체가 소멸될때 gmock은 자동으로 모든 예상 동작이 만족하는지 확인. 예상했던 함수가 예상했던 횟수만큼 호출 되었는지 검사(함수가 끝나서 mock 객체가 소멸할때까지 예상 했던 동작을 수행하지 않으면 테스트 실패).

#include "path/to/mock-turtle.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h"

// #1 : AtLeast 사용하기 위해 namespace 포함
using ::testing::AtLeast;                           

TEST(PainterTest, CanDrawSomething) {

  // #2 : tutle_mock 객체 생성
  MockTurtle tutle_mock;                                
  
  // #3 : tutle_mock 객체에 예상 동작 설정
  // tutle_mock 객체는 이 테스트에서 PenDown를 최소 한번 호출 할 것이다
  EXPECT_CALL(tutle_mock, PenDown()).Times(AtLeast(1));
      
  // 테스트 진행
  // #4 : tutle_mock 객체를 이용하여 테스트 코드 실행, 
  //      tutle_mock 객체가 PenDown 말고 다른 메소드 호출 하거나
          PenDown를 예상하지 못한 인자로 호출하면 바로 테스트 실패
  // #5 : TEST 메서드가 종료되어 tutle_mock이 소멸될때까지 tutle_mock이 PenDown을 호출하지 않으면 테스트 실패
  Painter painter(&tutle_mock);
  EXPECT_TRUE(painter.DrawCircle(0, 0, 10));
}

mock 행동 정의

  • mock 개체의 행동을 정의하기 위해서 2가지 생성자 있음
    • ON_CALL, EXPECT_CALL
  • ON_CALL
    • 호출 되었을때 어떻게 행동해야 하는지 정의(stub)
    • 호출하는 메소드에 대해서는 예상 동작을 설정하지 않기에 예상 동작이 어긋나서 테스트가 실패할 일은 없음
    ON_CALL(factory, DoMakeTurtle) // factory 객체의 DoMakeTurtle가 호출될때
        .WillByDefault(Return(MakeMockTurtle()));// MakeMockTurtle() 반환
  • EXPECT_CALL
    • EXPECT_CALL은 동작을 정의할 뿐만 아니라 주어진 횟수, 순서, 인수로 메소드가 호출될 것이라는 예상 동작 설정.
    • 예상 동작과 어긋나게 객체가 행동하면 테스트 실패
    • EXPECT_CALL은 테스트 중인 코드의 동작에 제약 조건을 추가하는 역할이다
    EXPECT_CALL(turtle, GetX()) // turtle 객체의 GetX() 호출될때
      .Times(5) // 5번 호출 될것이며(예상 동작)
      .WillOnce(Return(100)) //처음은 100 반환
      .WillOnce(Return(150)) //두번째는 150 반환
      .WillRepeatedly(Return(200)); // 그 이후부터는 200 계속 반환
  • ON_CALL, EXPECT_CALL 기대치 뒤에 동작 정의 가능
    • .WillOnce, .WillRepeatedly를 호출하여 이 mock 객체의 함수가 호출되었을때 어떻게 동작해야 할지 정의 가능

주의 1 : 파라미터로 들어가는 타입에 콤마가 있으면 컴파일 안됨

class MockFoo {
public:
  // 컴파일 안됨!, std::pair<bool, int>
  MOCK_METHOD(std::pair<bool, int>, GetPair, ());  
  // 컴파일 안됨!, std::map<int, double>
  MOCK_METHOD(bool, CheckMap, (std::map<int, double>, bool));
};

, 떄문에 구획을 나누는데 어려움이 있음
  • solution 1
class MockFoo {
public:
  MOCK_METHOD((std::pair<bool, int>), GetPair, ());
  MOCK_METHOD(bool, CheckMap, ((std::map<int, double>), bool));
};

- ()로 파라미터를 묶어 주면 됨
- argument나 리턴 타입에 ()를 묶는것은 일반적으로 C++에서 불가능 하지만 MOCK_METHOD가 ()를 제거해서 컴파일 됨
  • solution 2
class MockFoo {
public:
  using BoolAndInt = std::pair<bool, int>;    
  MOCK_METHOD(BoolAndInt, GetPair, ());
  using MapIntDouble = std::map<int, double>;
  MOCK_METHOD(bool, CheckMap, (MapIntDouble, bool));
};
- using 사용

주의 2 : MOCK_METHOD 는 언제나 public으로 두어야 한다.

  • 대상 메소드가 protected 또는 private 이어도 mock 메소드는 public으로 두어야 한다.
  • public으로 두면 ON_CALL, EXPECT_CALL에서 mock 메소드에 접근 가능하다.
class Foo {
public:
  ...
  virtual bool Transform(Gadget* g) = 0;
protected:
  virtual void Resume();
private:
  virtual int GetTimeOut();
};

class MockFoo : public Foo {
public:
  ...
  MOCK_METHOD(bool, Transform, (Gadget* g), (override));
  
  // Resume, GetTimeOut이 protected, private이어도
  // public 섹션에 두어야 한다.
  MOCK_METHOD(void, Resume, (), (override));
  MOCK_METHOD(int, GetTimeOut, (), (override));
};

TIP 1 : mock 클래스에 템플릿을 사용할 수 있다.

template <typename Elem>
class StackInterface {
  ...
  // Must be virtual as we'll inherit from StackInterface.
  virtual ~StackInterface();

  virtual int GetSize() const = 0;
  virtual void Push(const Elem& x) = 0;
};

//템플릿 사용
template <typename Elem>
class MockStack : public StackInterface<Elem> {
  ...
  MOCK_METHOD(int, GetSize, (), (override));
  MOCK_METHOD(void, Push, (const Elem& x), (override));//템플릿 타입 사용
};
  • 템플릿을 잘 활용하면 제품 코드와 테스트 코드를 작성할때 서로의 의존성 없이 작성 가능
// CreateConnection, PacketReader에 대한 제품 코드와 테스트 코드 필요

template <class PacketStream>
void CreateConnection(PacketStream* stream) { ... }

template <class PacketStream>
class PacketReader {
public:
  void ReadPackets(PacketStream* stream, size_t packet_num);
};
// 제품 코드
CreateConnection<ConcretePacketStream>() 
PacketReader<ConcretePacketStream>()
//테스트 코드 1
CreateConnection<MockPacketStream>() 
PacketReader<MockPacketStream>()

//테스트 코드 2
MockPacketStream mock_stream;
EXPECT_CALL(mock_stream, ...)...;
.. set more expectations on mock_stream ...
PacketReader<MockPacketStream> reader(&mock_stream);
... exercise reader ...      

TIP 2 : 일반 메소드에 대한 mock

  • virtual 메소드가 아닌 메소드도 mock 가능 하다.
  • 일반 메소드를 mock 할때는 override를 빼주면 됨
  • virtual 처럼 클래스를 상속받지는 않는다. 대신 제품 클래스와 같은 메소드 시그니처를 mock 클래스에서 정의
  • 일반 메소드를 mock 하면 mock 하고 싶은 메소드만 선별적으로 가져 올 수 있다.
//제품 클래스
class ConcretePacketStream {
public:
  void AppendPacket(Packet* new_packet);
  const Packet* GetPacket(size_t packet_number) const;
  size_t NumberOfPackets() const;
  ...
};

class MockPacketStream {
public:
  // 제품 클래스로부터 상속 받지 않았다.
  // AppendPacket를 mock하지 않았다
  MOCK_METHOD(const Packet*, GetPacket, (size_t packet_number), (const));//override 없음
  MOCK_METHOD(size_t, NumberOfPackets, (), (const));
  ...
};    

TIP 3 : 일반 메소드를 mock

  • 멤버 메소드가 아닌 메소드, C 스타일 static 메소드 같은 일반 메소드는 mock 할 수 없다
  • mock 하고 싶다면 interface에 재정 필요
  • 일반 메소드를 직접 호출하는 대신 interface에 선언한 후 이를 클래스가 구현하여 클래스에서 호출 해야한다.
  • 일반 메소드를 추상화 한것임
// OpenFile 이라는 일반 함수를 mock 하고 싶을때

// OpenFile에 대한 추상화
class FileInterface {
public:
  ...
  virtual bool Open(const char* path, const char* mode) = 0;
};

// 제품 코드
class File : public FileInterface {
public:
  ...
  bool Open(const char* path, const char* mode) override {
    // OpenFile 직접 호출 하는 대신 File의 Open 호출 해야함
    return OpenFile(path, mode);
  }
};

// mock
class MockFile : public FileInterface {
public:
  MOCK_METHOD(bool, Open, (const char* path, const char* mode), (override));
};

- virtual 함수에 대한 성능과 프로파일링에 대해 우려가 있을 경우 non-virtual 메소드로 mock 할 수 있다.  

EXPECT_CALL

  • EXPECT_CALL()을 이용하여 mock 객체에 함수 호출을 설정 하는 것은 이 함수가 호출이 된것이 아니라 미래에 호출이 발생할 것이라는 예측이다

EXPECT_CALL 설정시 주의

  • 한 테스트 내에서 EXPECT_CALL 여러번 호출하면 실패할 수 있다.
  • 기대치(expection)을 너무 업격하게 하면 테스트를 변경 하였을때 의도치 않게 테스트가 깨짐
  • 기대치(expection)을 너무 느슨하게 하면 버그를 놓칠 가능성 있음

Times()

  • EXPECT_CALL() 다음에 Times()를 지정 할 수 있다.
  • Times()를 호출하여 예상되는 함수가 몇번 호출 될것인지 지정 가능
  • Times(0)로 지정하면 테스트 안에서 해당 함수를 호출할 경우 테스트 실패
  • Times()가 없는 경우 해석되는 방법
    • WillOnce() 또는 WillRepeatedly()가 EXPECT_CALL() 이후에 호출되지 않으면 추론된 카디널리티는 Times(1)
    • n개의 WillOnce()가 있지만 WillRepeatedly()가 없는 경우(n >= 1인 경우) 카디널리티는 Times(n)
    • n개의 WillOnce()와 하나의 WillRepeatedly()가 있는 경우(여기서 n >= 0), 카디널리티는 Times(AtLeast(n))

mock 행동 정의 해석시 주의 사항

  • EXPECT_CALL()는 선언 부분에서 오직 한번만 해석 된다.
using ::testing::Return;
...
int n = 100;
EXPECT_CALL(tutle_mock, GetX())
    .Times(4)
    .WillRepeatedly(Return(n++));//100, 101, 102, 103 호출 ?? No
    
100, 101, 102, 104가 아니라 100 이 4번 호출되는 것으로 설정
EXPECT_CALL은 한번만 해석 된다. !!!
  • Times() 없는 상태에서 애매한 해석
using ::testing::Return;
...
EXPECT_CALL(tutle_mock, GetY())
  .WillOnce(Return(100))
  .WillOnce(Return(200))        //GetY가 최소 2번 호출되며(100, 200 반환)
  .WillRepeatedly(Return(300)); //3번째 부터 300만 반환
    
Time이 없어도 gmock이 알아서 해석을 하여 Times()를 지정한다.
  • WillOnce 갯수만큼 처리된 이후부터는 기본값으로 동작한다.(0, false 반환)
using ::testing::Return;
...
EXPECT_CALL(tutle_mock, GetY())
  .Times(4)
  .WillOnce(Return(100));//100이 4번 호출될 것을 기대?? No

4번 호출될 것이며 처음 한번은 100을 반환할 것이고 이후부터는 기본값을 반환한다.
  • EX)
TEST(TestCaseName, TestName) {
  MockTurtle turtle_mock;
  EXPECT_CALL(turtle_mock, GetY())// GetY 호출에 대한 기대치
    .Times(2)                     // 2번 호출될 것을 기대, 2번 호출되지 않으면 실패
    .WillOnce(Return(101))        // GetY 첫번째 호출에서 turtle_mock은 101 반환하도록 정의
    .WillOnce(Return(200));       // GetY 두번째 호출에서 turtle_mock은 200 반환하도록 정의
  std::cout << turtle_mock.GetY() << std::endl;// 101
  std::cout << turtle_mock.GetY() << std::endl;// 200
}

turtle_mock.GetY() 3번 호출하면 실패
.Times(3)으로 바꾸면 3번 호출해도 성공 하지만 경고 발생
using ::testing::Return;
...
EXPECT_CALL(tutle_mock, GetX())
  .Times(5)                       //GetX가 5번 호출될것이다.
  .WillOnce(Return(100))          //이 객체는 100을 처음 리턴하고 
  .WillOnce(Return(150))          //150을 두번째로
  .WillRepeatedly(Return(200));   //이 후부터는 계속 200을 리턴할 것이다.
  • 테스트에 여러 기대치가 있을때
    • mock 메서드가 호출되면 gmock은 역순으로 테스트에 정의된 기대치를 검색 한다.
    • 인수와 일치하는 활성된 기대값을 찾으면 검색을 중지한다.
    • gmock이 예상과 반대 순서로 일치하는 항목을 검색하는 이유
      • mock 객체의 생성자 또는 테스트 픽스처의 설정 단계에서 기본 기대값을 설정한 다음 테스트 본문에 더 구체적인 기대치를 작성하는 구조로 만들기 위해
      • 따라서 동일한 테스트에 대해 두 가지 기대가 있는 경우 더 구체적인 매처가 있는 것을 다른 일반적인 규칙 뒤에 두는것으로 응용한다.
using ::testing::_;
...
EXPECT_CALL(turtle, Forward(_));  // #1
EXPECT_CALL(turtle, Forward(10))  // #2
  .Times(2);
  
Forward(10)
Forward(10)
//Forward(10) // 3번째 호출하면 #2의 기대치가 포화 상태이기에 테스트 실패할 것이다.
Forward(20) // 그러나 3번째에 20이 호출되면 #1의 기대치에 매칭되기에 테스트가 실패하지 않는다.

상한 위반

  • Times(n)로 지정된 횟수보다 더 많이 호출된 경우(일치하는 기대치가 더 이상 호출을 받을 수 없다)
using ::testing::_;
...
EXPECT_CALL(tutle_mock, Forward(_));  // #1
EXPECT_CALL(tutle_mock, Forward(10))  // #2
  .Times(2);


Forward(10) 연속으로 3번 호출할 경우 -> 실패
- 3번 모두 #2 기대값으로 적용되서 검사
- 3 번째 호출 되었을때, 기대(#2)가 포화되었기 때문에 세 번째는 오류가 처리

Forward(10) 연속으로 2번 호출, 세 번째 호출은 Forward(20) -> 성공
- 2번째 까지 #2 처리
- 3번째는 #2로 조건이 맞지 않기 떄문에 #1으로 처리, 성공  
  • 기대치 포화 상태가 의미하는것

    • 기대치는 아래에서 위로 해석되는 필터 구조이다
    • 기대치가 상한에 도달한 후에도 포화된 기대치는 계속 활성화 상태로 유지됨.
    • 이것은 사양의 의미에 영향을 미치고 다른 많은 mocking 프레임워크에서 수행되는 방식과 다르기 때문에 기억해야 할 중요한 규칙이다.
  • 포화된 기대치 비활성화

    • 포화된 기대치를 비활성화 해서 테스트를 성공하도록 바꿀 수 있다.
// 실패
TEST(TestCaseName, TestName) {
  MockTurtle tutle_mock;
  EXPECT_CALL(tutle_mock, GetX())                #1
    .WillOnce(Return(10));
  EXPECT_CALL(tutle_mock, GetX())                #2 : 2번째 호출이 상한에 걸려서 테스트 실패
    .WillOnce(Return(10));        

  std::cout << tutle_mock.GetX() << std::endl;
  std::cout << tutle_mock.GetX() << std::endl;
}
// 성공
TEST(TestCaseName, TestName) {
  MockTurtle tutle_mock;
  EXPECT_CALL(tutle_mock, GetX())                #1
    .WillOnce(Return(10));
  EXPECT_CALL(tutle_mock, GetX())
    .WillOnce(Return(10)).RetiresOnSaturation(); #2 : 상한에 걸리면 비활성화, 2번째 호출은 #1에 매칭

  std::cout << tutle_mock.GetX() << std::endl;
  std::cout << tutle_mock.GetX() << std::endl;
}
  • for 문에서 상한 위반
// tutle_mock이 10, 20, 30, ... n * 10으로 호출되는 기대치를 설정하고 싶을때

using ::testing::Return;
...
for (int i = 3; i > 0; i--) {
  EXPECT_CALL(tutle_mock, GetX())
    .WillOnce(Return(10*i));
}
/*
EXPECT_CALL(mock, get_y())
  .WillOnce(::testing::Return(30));
EXPECT_CALL(mock, get_y())
  .WillOnce(::testing::Return(20));
EXPECT_CALL(mock, get_y())
  .WillOnce(::testing::Return(10))
*/


해석 : 10, 20, 30, ... 순으로 해석될 것이다 ?? No
기대치는 기본적으로 선언 시점에 해석됨
- 마지막(최신) EXPECT_CALL(10)으로 선언되어 있다
- 따라서 두 번째 tutle_mock.GetX()가 호출되면 
마지막(최신) EXPECT_CALL() 문이 처리하고 즉시 "상한 위반" 오류가 발생
// 올바른 방법
// 조건 포화되면 기대값을 비활성화 시키면 된다.

using ::testing::Return;
...
for (int i = n; i > 0; i--) {
  EXPECT_CALL(tutle_mock, GetX())
    .WillOnce(Return(10*i))
    .RetiresOnSaturation();
}

for 안에서 EXPECT_CALL을 호출하려 한다면 RetiresOnSaturation를 사용해서 
포화된 기대치를 비활성화 시켜야 한다.  
// 더 좋은 방법

using ::testing::InSequence;
using ::testing::Return;
...
{
  InSequence s;// 역방향으로 열거할 필요 없게 만듬
  for (int i = 1; i <= n; i++) {
    EXPECT_CALL(tutle_mock, GetX())
      .WillOnce(Return(10*i))
      .RetiresOnSaturation();
  }
}

순서를 지키게끔 강제 함(10,20,30...)
  • EX)
// 개선 전
TEST(TestCaseName, TestName) {
  MockTurtle tutle_mock;
  {
    for (int i = 2; i > 0; i--) {     <-- 역순
      EXPECT_CALL(tutle_mock, GetX())
        .WillOnce(Return(10 * i))
        .RetiresOnSaturation();
      EXPECT_CALL(tutle_mock, GetY())
        .WillOnce(Return(11 * i))
        .RetiresOnSaturation();
    }
  }

  std::cout << tutle_mock.GetX() << std::endl;  //10      <-- 순서 지키지 않았지만 테스트 통과
  std::cout << tutle_mock.GetX() << std::endl;  //20
  std::cout << tutle_mock.GetY() << std::endl;  //11
  std::cout << tutle_mock.GetY() << std::endl;  //22
}  

// 개선 후
TEST(TestCaseName, TestName) {
  MockTurtle tutle_mock;
  {
    InSequence s;
    for (int i = 1; i <= 2; i++) {      <-- 일부로 역순으로 할 필요 없음
      EXPECT_CALL(tutle_mock, GetX())
        .WillOnce(Return(10 * i))
        .RetiresOnSaturation();
      EXPECT_CALL(tutle_mock, GetY())
        .WillOnce(Return(11 * i))
        .RetiresOnSaturation();
    }
  }

  std::cout << tutle_mock.GetX() << std::endl;  //10   <-- GetX, GetY 순서를 지켜야 테스트 통과됨
  std::cout << tutle_mock.GetY() << std::endl;  //11
  std::cout << tutle_mock.GetX() << std::endl;  //20
  std::cout << tutle_mock.GetY() << std::endl;  //21
}  

호출 순서에 대한 기대치 설정

  • 호출 순서를 지키는 것에 대한 기대치를 설정 할 수 있다.
  • InSequence seq; 추가하면 순서를 강제할 수 있다.
using ::testing::InSequence;
...
TEST(FooTest, DrawsLineSegment) {
  ...
  {
    InSequence seq;

    EXPECT_CALL(tutle_mock, PenDown());
    EXPECT_CALL(tutle_mock, Forward(100));
    EXPECT_CALL(tutle_mock, PenUp());
  }
  Foo();
} 

일부만 순서를 지키게 할 수 있다.
  • 상대적인 호출 순서를 지정할 수 있다.
using ::testing::Sequence;
...
Sequence s1, s2;

EXPECT_CALL(foo, A())
  .InSequence(s1, s2);
EXPECT_CALL(bar, B())
  .InSequence(s1);
EXPECT_CALL(bar, C())
  .InSequence(s2);
EXPECT_CALL(foo, D())
  .InSequence(s2);
  
specifies the following DAG (where s1 is A -> B, and s2 is A -> C -> D):

    +---> B
    |
A --|
    |
    +---> C ---> D
    
그러나 사용 하는 것을 비추한다.. 테스트를 굉장히 어렵게 만든다.

포괄적인 기대치 설정

  • 메소드와 Times(AnyNumber())에 대한 포괄적인 기대로 시작하는 것은 매우 일반적이다
    • 이렇게 하면 메서드에 대한 모든 호출을 처리 가능
  • 이것은 전혀 언급되지 않은 메서드(Uninteresting method)에는 필요하지 않지만 다른 호출은 괜찮은 메서드에는 유용합니다.
  • 포괄적인 기대치 설정할때 상한 위반을 주의 해야 한다.
using ::testing::_;
using ::testing::AnyNumber;
...
EXPECT_CALL(tutle_mock, GoTo(_, _))  // #1, 포괄적인 기대치
    .Times(AnyNumber());
EXPECT_CALL(tutle_mock, GoTo(0, 0))  // #2
    .Times(2);

GoTo(0,0)가 3번 호출 되었을 경우
- 3번의 호출이 #2와 일치하는지 확인
- 상한 위반 발생

- 이를 회피하려면 #2 기대치가 포화되었을때 비활성화 시키면 됨

컴파일 성능

  • mock 클래스의 생성자와 소멸자를 컴파일 하는데 시간이 오래 걸림
  • mock이 다양한 인터페이스를 가진 메서드, 생성자들이 많을 수록 컴파일 느려질 것이다.
  • 생성자, 소멸자 구현이 바뀌면 컴파일 다시 해야하는 부분이 많기에 생성자, 소멸자 구현은 헤더파일에 넣으면 안됨

참고

profile
mohadang
post-custom-banner

0개의 댓글