Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use gmock to mock a template method from a class?

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..

like image 769
Bryan Fok Avatar asked May 11 '17 09:05

Bryan Fok


1 Answers

  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.

like image 167
PiotrNycz Avatar answered Oct 13 '22 11:10

PiotrNycz