How to use gmock to mock a template method from a class?
Asked Answered
S

2

8

How to use gmock to mock a template method (not a template class) for a class? Example a class like this, I want to mock this class, and this template method..

class A{
public:
  template<EnumType ENUM_VALUE>
  int getType(int val);
};

I know how to mock a class with non-virtual methods, or mock a templated class, but i dont know how to mock a non-templated class with a templated method..

Standush answered 11/5, 2017 at 9:57 Comment(2)
FYI: function(method) template cannot be virtual in C++ - so do not need to add to description of function template that it is not virtualMethanol
oops thanks. my mistakeStandush
M
2
  1. First much better solution is to use the implementation of this function A::getType - maybe it does not have to be mocked? E.g.: if it just returns some value that is set in constructor - then just construct A in the way that is needed in your test case:
class A{
public:
  A(int a) : a(a) {}
  template<typename T>
  int getType(int val)
  {
      return a + val;
  }
private:
  int a;
};

 TEST(...)
 {
      A a(TYPE_VALUE_FOR_TEST);
      ...
 }
  1. If it cannot be done that way - then you might consider to have some instrumentation for UT that is switched with preprocessor macros:
 #ifdef TESTING
 namespace Testing
 {
 using std::pair<std::type_index, int> AGetTypeKey;
 std::map<AGetTypeKey, int> AGetTypeExpectedValues;
 template <typename T>
 void expectAGetType(int inputValue, int expectedResult)
 {
      AGetTypeExpectedValues[AGetTypeKey(std::type_index(typeid(T)), inputValue)] = expectedResult;
 }
 template <typename T>
 int getAGetType(int value)
 {
      return AGetTypeExpectedValues[AGetTypeKey(std::type_index(typeid(T)), inputValue)];
 }
 }
 #endif

class A{
public:
  A(int a) : a(a) {}
  template<typename T>
  int getType(int val)
  {
  #if TESTING
      return Testing::getAGetType<T>(val);
  #else
      // your "normal" implementation
      ...
  #endif
  }
private:
  int a;
};

 // compiled with -DTESTING=1
 #ifndef TESTING
 #error ...
 #endif
 TEST(...)
 {
      Testing::expectAGetType<float>(EXPECTED_INPUT_VALUE,
                                     TYPE_VALUE_FOR_FLOAT);
      ...
 }

Regarding point-2 - of course all testing code should be carefully separated from "normal code" - e.g. in some separated header files.

It is worth to say that none of these solution is perfect - and this second solution might not be 100% reliable as you would test not real code but some testable version of it.

Maybe you should start from rethinking your design - as it seems the design was not completed with "design for testability" in mind.

Methanol answered 16/5, 2017 at 12:17 Comment(1)
function signature was a dummy example. Dont think either solution suitable for me. but thanks.Standush
S
0

I end up doing a relay to mock the method

E.g.

class MOCK_A{
public:
  template<Enum ENUM_VALUE>
  int getType(int val){
    getType(val, ENUM_VALUE);
  }
  
  MOCK_METHOD1(getType, int(int val, Enum enum_value));
};
Standush answered 25/5, 2017 at 5:56 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.