만약 mocking 대상이 기본적인 호출방식을 사용하지 않는다면, 이를 gMock에 알려줘야 한다. 예를 들어 Windows의 `STDMETHODCALLTYPE` 같은 경우에는 `ULONG STDMETHODCALLTYPE AddRef()`과 같은 형태로 function이 선언된다. 사용자는 gMock이 이러한 내용을 알 수 있도록 `MOCK_METHOD`의 4번째 parameter를 통해 관련내용을 전달해야 한다.
특정 method의 default action만 변경하려면 `ON_CALL()`을 사용하면 된다. `ON_CALL()`은`EXPECT_CALL()`과 사용방법이 비슷하며 default behavior를 변경하기 위한 목적으로 사용한다. 더 자세한 정보는 [여기](cook_book.md#default-action을-상황에-따라-변화시키기)를 참조하자.
| `TypedEq<type>(value)` | `argument`가 `type`이라는 타입을 가지며 그 값도 `value`와 같기를 기대한다. 기본적으로 `Eq(value)`와 동일한 기능을 하지만 타입지정이 가능하기 때문에 mock function이 overloaded 되었을 때 유용하게 사용할 수 있다. |
대부분의 matcher들은 자신이 실행되는 시점에 `value`에 대한 *복사본을 생성하고 내부적으로 보관한다.* (`Ref()`는 제외) 이렇게 복사본을 만드는 이유는 `value`가 추후에 수정되거나 소멸될 것에 대비하기 위함이다. 그러다가 실제로 mock function이 호출되면 위에서 만들어 놓은 복사본과 전달된 argument를 서로 비교하게 된다. 이런 안전장치가 있기 때문에 `EXPECT_CALL`이 수행된 이후에는 `value`가 수정되더라도 영향을 받지 않게 된다. 한 가지 유의할 점은 copy constructor가 없는 `value`는 (당연하게도) compile error가 발생한다는 것이다. 이 문제를 해결하기 위해서 `value`를 `ByRef()`로 감싸서 참조형식으로 전달하는 것도 가능하다. 예를 들면 `Eq(ByRef(non_copyable_value))`와 같이 구현할 수 있을 것이다. 다만, 이것은 복사본을 만드는 것이 아니기 때문에 주의해서 사용하기 바란다. 참조형식을 사용하게 되면 `value`의 값에 따라 matcher의 동작도 달라진다는 점을 기억하자.
위의 floating-point matcher들은 ULP-based 비교를 수행한다. googletest의 floating-point assertion에서도 이와 동일한 방법을 사용하고 있다. 이 때의 오차범위는 expected value의 절대값을 기반으로 자동으로 계산된다. 다음으로 `DoubleEq`, `FloatEq`를 사용해서 2개의 NaN를 비교한다면 IEEE 표준에 따라 `false`를 반환하도록 되어 있다. 만약 NaN 2개를 비교했을 때 `true`가 반환되기를 원한다면 `NanSensitive*`로 시작하는 버전을 사용하기 바란다.
| `DoubleNear(a_double, max_abs_error)` | `argument`는 `double` 타입이며 그 값은 `a_double`과 *거의 같다.* (단, absolute error <= `max_abs_error`) 두 개의 NaN을 비교할 때는 같지 않다고 판단한다. |
| `FloatNear(a_float, max_abs_error)` | `argument`는 `float` 타입이며 그 값은 `a_float`와 *거의 같다.* (단, absolute error <= `max_abs_error`) 두 개의 NaN을 비교할 때는 같지 않다고 판단한다. |
| `NanSensitiveDoubleNear(a_double, max_abs_error)` | `argument`는 `double` 타입이며 그 값은 `a_double`과 *거의 같다.* (단, absolute error <= `max_abs_error`) 두 개의 NaN을 비교할 때는 같다고 판단한다. |
| `NanSensitiveFloatNear(a_float, max_abs_error)` | `argument`는 `float` 타입이 그 값은 `a_float`와 *거의 같다.* (단, absolute error <= `max_abs_error`) 두 개의 NaN을 비교할 때는 같다고 판단한다. |
`ContainsRegex()`, `MatchesRegex()`에 사용되는 정규식 문법은 [이곳](../../../googletest/docs/kr/advanced.md#정규식-문법)에 정의되어 있으며 `StrCaseEq()`, `StrCaseNe()`, `StrEq()`, `StrNe()`은 wide string 타입을 사용해도 잘 동작한다.
STL-style container들은 대부분 `==` 연산자를 제공하고 있다. 따라서 `Eq(expected_container)` 또는 `foo(expected_container)`와 같이 구현하면 별다른 조치를 취하지 않더라도 잘 동작할 것이다. 혹시나 보다 다양한 방법으로 container를 비교하고 싶은 사용자는 아래 표를 확인하기 바란다. 이렇게 추가적으로 제공되는 matcher를 통해서 사용자가 처한 상황에 맞게 좀 더 유연한 방법을 선택할 수 있을 것이다.
| `BeginEndDistanceIs(m)` | argument로 전달된 container의 `begin()`, `end()`간의 차이(*즉, container의 size*)를 matcher `m`통해 비교한다. 예를 들어`BegintEndDistanceIs(2)` 또는 `BeginEndDistanceIs(Lt(2))`와 같이 사용하면 된다. 만약, 해당 container가 `size()`를 정의하고 있다면 `SizeIs(m)`를 사용해도 된다. 기능자체는 동일하다. |
| `ContainerEq(container)` | 기본적인 동작은 `Eq(container)`와 유사하다. 단, failure message에 어떤 element가 서로 다른지와 같은 추가정보를 출력해준다. |
| `Contains(e)` | argument로 전달된 container에 `e`를 만족하는 element가 있는지 확인한다. 여기서 `e`는 값일 수도 있고 matcher일 수도 있다. |
| `Each(e)` | argument로 전달된 container의 *모든* element가 `e`를 만족해야 한다. 여기서 `e`는 값일 수도 있고 matcher일 수도 있다. |
| `IsTrue()` | argument로 전달된 container가 `true`이기를 기대한다. 단, container가 boolean 타입으로 사용가능한 경우만 해당된다. |
| `IsFalse()` | argument로 전달된 container가 `false`이기를 기대한다. 단, container가 boolean 타입으로 사용가능한 경우만 해당된다. |
| `SizeIs(m)` | argument로 전달된 container의 size가 matcher `m`을 만족하는지 확인한다. `SizeIs(2)` 또는 `SizeIs(Lt(2))`와 같이 사용할 수 있다. |
| `ElementsAre(e0, e1, ..., en)` | argument로 전달된 container의 element들이 `e0`, `...`, `en`을 각각 만족하는지 비교한다. 여기서 `e`는 값일 수도 있고 matcher일 수도 있다. 허용되는 element 개수는 0~10개 까지이다. |
| `ElementsAreArray({ e0, e1, ..., en })`, `ElementsAreArray(a_container)`, `ElementsAreArray(begin, end)`, `ElementsAreArray(array)`, `ElementsAreArray(array, count)` | 기본적인 동작은 `ElementsAre()`과 유사하다. 단, `e0`, `e1`과 같은 expected element를 initializer_list, STL-style container, C-style array와 같은 다양한 방법으로 전달할 수 있다. |
| `UnorderedElementsAre(e0, e1, ..., en)` | 기본적인 동작은 `ElementsAre()`과 유사하다. 단, `argument`와 parameter의 element들을 순서대로 비교하지는 않는다. |
| `UnorderedElementsAreArray({ e0, e1, ..., en })`, `UnorderedElementsAreArray(a_container)`, `UnorderedElementsAreArray(begin, end)`, `UnorderedElementsAreArray(array)`, `UnorderedElementsAreArray(array, count)` | 기본적인 동작은 `UnorderedElementsAre()`과 유사하다. 단, `e0`, `e1`과 같은 expected element를 initializer_list, STL-style container, C-style array와 같은 다양한 방법으로 전달할 수 있다. |
| `Pointwise(m, container)` | argument로 전달된 container의 element 개수와 `container`의 element 개수가 같아야 한다. 이 때 2개의 container에 속한 모든 element들이 matcher `m`을 통해 비교된다. 이 때, 양측의 element는 2-tuples 형태로 matcher `m`에 전달된다. 예를 들어 `Pointwise(Le(), upper_bounds)`라는 코드가 있다면 이는 argument로 전달된 container의 element가 `upper_bounds`에 속한 element보다 작은지를 확인하게 된다. `Pointwise`와 관련해서는 표 아랫부분에도 추가적인 설명이 있다. |
| `UnorderedPointwise(m, container)`, `UnorderedPointwise(m, {e0, e1, ..., en})` | 기본적인 동작은 `Pointwise(m, container)`와 유사하다. 단, element들을 순서대로 비교하지 않는다. 순서에 관계없이 matcher `m`을 만족하면 된다. |
| `WhenSorted(m)` | argument로 전달된 container의 element들을 `<`operator 를 통해서 정렬하고(오름차순) 그 결과를 matcher `m`을 통해 비교한다. 이 때, 정렬은 gMock에서 자동으로 해준다. 예를 들어 `WhenSorted(ElementsAre(1,2,3))`라는 코드는 argument로 `1, 2, 3` 혹은 `2, 3, 1`과 같은 값들이 전달되어야 만족하게 된다. |
| `WhenSortedBy(comparator, m)` | 기본적인 동작은 `WhenSorted(m)`와 유사하지만 정렬방식을 변경할 수 있다. 예를 들어 `WhenSortedBy(std::greater<int>(), ElementsAre(3,2,1))`과 같이 사용하면 내림차순으로 정렬한 결과를 비교하게 된다. |
2. pointer + array size 형태로 array를 사용할 때 (예: `Bar(const T* buffer, int len)` -- 자세한 사용방법은 [multi-argument matchers](#multi-argument-matchers)에서 확인)
- Multi-dimensional array에도 사용 가능 (예: container의 element 각각이 array인 경우)
-`Pointwise(m, ...)`에 사용하기 위한 `m`을 구현할 때는 `::testing::tuple<T, U>`라는 tuple을 전달받아서 `T`, `U`를 비교하는 형태가 되어야 한다. 여기서 `T`와 `U`는 각각 actual container(argument)의 element type과 expected container(parameter)의 element type을 의미한다. 예를 들어, `Foo`라는 타입이 `operator==` 없이 `Equals()`이라는 method만 제공한다면 해당 타입 2개를 비교하는 matcher는 아래처럼 구현하면 된다.
기본적으로 하나의 matcher는 *하나의 값만 비교한다.* 제목인 "multi-argument"라는 것도 사실은 *tuple*을 통해서 가능한 것이기 때문에 여전히 하나의 값을 비교한다고 주장해도 틀린말은 아닐 것이다. 어찌 됐든 아래 표에 있는 matcher들은 `(x, y)`형태의 tuple을 비교할 때 사용할 수 있다. 물론 사용자가 직접 tuple을 사용가능한 matcher를 구현해도 된다.
| `AllArgs(m)` | 사실 단순히 `m`이라고 구현하는 것과 동일하다. 즉, `EXPECT_THAT(std::make_tuple(2,1), Gt());`과 `EXPECT_THAT(std::make_tuple(2,1), AllArgs(Gt());`은 동일한 의미이다. `.With`와 함께 `.With(AllArgs(m))`와 같이 사용하는 것도 좋다. |
| `Args<N1, N2, ..., Nk>(m)` | 전달된 tuple에서 몇 개만 선택하고 이들을 matcher `m`을 통해 비교한다. argument의 index는 0부터 시작한다. 즉, `EXPECT_THAT(std::make_tuple(1,2,3), Args<1, 2>(Eq())`이라는 코드는 값 `2`와 `3`이 같은지를 비교한다. |
1.`MATCHER*` macro는 function이나 class 내부에서는 사용하면 안 된다.
1. Matcher의 body`{}`를 구현할때는 *purely functional*하게 구현해야 하며 어떤 side-effect도 가지면 안 된다. 즉, 순수하게 matcher로 전달되는 argument와 parameter의 값을 읽고 비교해서 그 결과를 알려주는 동작만 수행해야 한다. 또한, 프로그램의 다른 부분을 수정해서는 안 되며 argument, parameter를 제외한 외부의 다른 정보에 영향을 받아서도 안 된다. 자신의 기능만 독립적으로 수행해야 한다.
1.`PrintToString(x)`를 사용하면 `x`가 어떤 타입이라도 string으로 변환시킬 수 있다.
| `SetArgumentPointee<N>(value)` | `SetArgPointee<N>(value)`과 동일하지만 deprecated 되었습니다. gMock v1.7.0 이후에 삭제될 예정이다. |
| `SetArrayArgument<N>(first, last)` | [`first`, `last`)에 저장되어 있는 값을 `N`번째(0부터 시작) argument가 가리키는 array에 저장한다. Array는 pointer 혹은 iterator가 될 수 있다. 이 때, action은 [`first`, `last`) 가 가리키는 값을 직접 소유하지는 않는다. |
`Invoke(callback)`와 `InvokeWithoutArgs(callback)`과 같은 action은 전달받은 `callback`에 대한 소유권을 갖는다. 따라서 해당 action과 `callback`의 life-time은 동일하다. 그리고 `callback`의 타입은 base callback이어야만 한다. 아래 예제와 같이 dervied callback을 사용하면 compile error가 발생한다.
위 action은 대상 mock function으로 전달된 2번째 argument를 호출할 것이다. 그러므로 mock function의 3번째(index는 2) argument는 callable이 되어야 한다. 다음으로 해당 callable을 호출할 때 3개의 argument(숫자 `5`, 문자열 `"Hi"`, `foo`라는 변수의 참조)도 같이 전달하게 된다.
**Note:** 기술적인 문제로 인해 `DoDefault()`를 composite action에 사용할 수는 없다. 그렇게 구현하면 runtime error가 발생할 것이다. Composite action이란 여러 개의 action을 조합하여 사용하는 것을 의미하며 바로 아래에서 계속 설명한다.
위 코드는 `Bar()`가 `all_inits`에 포함된 expectation들이 모두 수행된 이후에 호출되기를 기대한다는 의미이다. 그러나 `all_inits `에 포함된 expectaion들간의 호출순서는 신경쓰지 않는다. 오직 `Bar()`가 그 후에 호출되기만 하면 된다.
위의 코드는 `Reset()`이 다른 2개의 function인 `GetSize()`, `Describe()`보다 먼저 호출되기를 기대한다는 의미이다. 그 외의 다른 호출순서는 없다. 예를 들면 `GetSize()`, `Describe()`라는 2개의 function은 누가 먼저 호출되든 상관이 없다. 왜냐하면 2개의 function은 동일한 sequence로 연결되지 않았기 때문이다.