0

I have coded a demo mock using google mock. The issue is that it is failing and not properly mocking. I cannot understand the issue here.

Code:

test/mock_turtle_test.cc

#include "mock_turtle.h"
#include "../painter.h"
#include <gtest/gtest.h>

using  ::testing::_;
using  ::testing::AtLeast;
using  ::testing::Return;
ACTION(MyException)
{
        throw(error_k());
}
TEST(PainterTest, CanDrawSomething) {
  Painter painter;
  EXPECT_CALL(*(painter.getTurtle()), PenDown())
      .Times(AtLeast(1))
      .WillOnce(MyException())
      .WillRepeatedly(Return(5));
  EXPECT_TRUE(painter.DrawCircle(0, 0, 10));
}

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

inc/mock_turtle.h

#pragma once
#include <cstdlib>
#include "turtle.h"
#include <gmock/gmock.h>

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

inc/turtle.h

#pragma once

class FakeTurtle {

public:
  virtual ~FakeTurtle() {}
  virtual void PenUp() {};
  virtual int PenDown() {};
  virtual void Forward(int distance) {};
  virtual void Turn(int degrees) {};
  virtual void GoTo(int x, int y) {};
  virtual int GetX() const {};
  virtual int GetY() const {};

};

painter.h

#pragma once
#include "turtle.h"
#include <cerrno>

class error_k
{
public:
    error_k() : errnum(EAGAIN){}
    int num() const
    {
        return errnum;
    }
private:
    int errnum;
};

class Painter
{
        Turtle* turtle;
public:
        Painter() : turtle(new Turtle){}
    Turtle* getTurtle(){
        return turtle;
    }
        bool DrawCircle(int, int, int){
        int rep = 10;
        int ret = 0;
        do{
            try{
                std::cout << "calling PenDown() : rep = " <<
                    rep << " , ret = " << ret << std::endl;
                        ret = turtle->PenDown();
                if(ret > 0)
                    return true;
            }catch(error_k err )
            {
                std::cout << "Caught Exception (" <<
                    err.num() << "): rep = " <<
                    rep << " , ret = " << ret << std::endl;

                delete turtle;
                turtle = new Turtle();
            }
        }while(rep-- > 0 && ret == 0); 
                return false;
        }
    ~Painter(){
        delete turtle;
    }
};

CmakeLists.txt

cmake_minimum_required(VERSION 2.6)

# Locate GTest
find_package(GTest REQUIRED)
find_package(PkgConfig)
message(STATUS "gtest found: " ${GTEST_FOUND})
pkg_check_modules(GMOCK "gmock" REQUIRED)
message(STATUS "gmock found: " ${GMOCK_FOUND})

include_directories(${GTEST_INCLUDE_DIRS})

# Link runTests with what we want to test and the GTest and pthread library
add_executable(runTests test/mock_turtle_test.cc)
target_link_libraries(runTests ${GTEST_LIBRARIES} ${GMOCK_LIBRARIES} gmock gmock_main gtest gtest_main)
target_include_directories(runTests SYSTEM PRIVATE inc)
add_test(NAME runTests COMMAND runTests)
enable_testing()

Output:

$ ./runTests 
[==========] Running 1 test from 1 test suite.
[----------] Global test environment set-up.
[----------] 1 test from PainterTest
[ RUN      ] PainterTest.CanDrawSomething
calling PenDown() : rep = 10 , ret = 0
Caught Exception (11): rep = 10 , ret = 0
calling PenDown() : rep = 9 , ret = 0

GMOCK WARNING:
Uninteresting mock function call - returning default value.
    Function call: PenDown()
          Returns: 0
NOTE: You can safely ignore the above warning unless this call should not happen.  Do not suppress it by blindly adding an EXPECT_CALL() if you don't mean to enforce the call.  See https://github.com/google/googletest/blob/master/googlemock/docs/cook_book.md#knowing-when-to-expect for details.
calling PenDown() : rep = 8 , ret = 0

GMOCK WARNING:
Uninteresting mock function call - returning default value.
    Function call: PenDown()
          Returns: 0
NOTE: You can safely ignore the above warning unless this call should not happen.  Do not suppress it by blindly adding an EXPECT_CALL() if you don't mean to enforce the call.  See https://github.com/google/googletest/blob/master/googlemock/docs/cook_book.md#knowing-when-to-expect for details.
calling PenDown() : rep = 7 , ret = 0

GMOCK WARNING:
Uninteresting mock function call - returning default value.
    Function call: PenDown()
          Returns: 0
NOTE: You can safely ignore the above warning unless this call should not happen.  Do not suppress it by blindly adding an EXPECT_CALL() if you don't mean to enforce the call.  See https://github.com/google/googletest/blob/master/googlemock/docs/cook_book.md#knowing-when-to-expect for details.
calling PenDown() : rep = 6 , ret = 0

GMOCK WARNING:
Uninteresting mock function call - returning default value.
    Function call: PenDown()
          Returns: 0
NOTE: You can safely ignore the above warning unless this call should not happen.  Do not suppress it by blindly adding an EXPECT_CALL() if you don't mean to enforce the call.  See https://github.com/google/googletest/blob/master/googlemock/docs/cook_book.md#knowing-when-to-expect for details.
calling PenDown() : rep = 5 , ret = 0

GMOCK WARNING:
Uninteresting mock function call - returning default value.
    Function call: PenDown()
          Returns: 0
NOTE: You can safely ignore the above warning unless this call should not happen.  Do not suppress it by blindly adding an EXPECT_CALL() if you don't mean to enforce the call.  See https://github.com/google/googletest/blob/master/googlemock/docs/cook_book.md#knowing-when-to-expect for details.
calling PenDown() : rep = 4 , ret = 0

GMOCK WARNING:
Uninteresting mock function call - returning default value.
    Function call: PenDown()
          Returns: 0
NOTE: You can safely ignore the above warning unless this call should not happen.  Do not suppress it by blindly adding an EXPECT_CALL() if you don't mean to enforce the call.  See https://github.com/google/googletest/blob/master/googlemock/docs/cook_book.md#knowing-when-to-expect for details.
calling PenDown() : rep = 3 , ret = 0

GMOCK WARNING:
Uninteresting mock function call - returning default value.
    Function call: PenDown()
          Returns: 0
NOTE: You can safely ignore the above warning unless this call should not happen.  Do not suppress it by blindly adding an EXPECT_CALL() if you don't mean to enforce the call.  See https://github.com/google/googletest/blob/master/googlemock/docs/cook_book.md#knowing-when-to-expect for details.
calling PenDown() : rep = 2 , ret = 0

GMOCK WARNING:
Uninteresting mock function call - returning default value.
    Function call: PenDown()
          Returns: 0
NOTE: You can safely ignore the above warning unless this call should not happen.  Do not suppress it by blindly adding an EXPECT_CALL() if you don't mean to enforce the call.  See https://github.com/google/googletest/blob/master/googlemock/docs/cook_book.md#knowing-when-to-expect for details.
calling PenDown() : rep = 1 , ret = 0

GMOCK WARNING:
Uninteresting mock function call - returning default value.
    Function call: PenDown()
          Returns: 0
NOTE: You can safely ignore the above warning unless this call should not happen.  Do not suppress it by blindly adding an EXPECT_CALL() if you don't mean to enforce the call.  See https://github.com/google/googletest/blob/master/googlemock/docs/cook_book.md#knowing-when-to-expect for details.
calling PenDown() : rep = 0 , ret = 0

GMOCK WARNING:
Uninteresting mock function call - returning default value.
    Function call: PenDown()
          Returns: 0
NOTE: You can safely ignore the above warning unless this call should not happen.  Do not suppress it by blindly adding an EXPECT_CALL() if you don't mean to enforce the call.  See https://github.com/google/googletest/blob/master/googlemock/docs/cook_book.md#knowing-when-to-expect for details.
/home/preetam/Desktop/gmock/cpp_mock_ptr/test/mock_turtle_test.cc:18: Failure
Value of: painter.DrawCircle(0, 0, 10)
  Actual: false
Expected: true
[  FAILED  ] PainterTest.CanDrawSomething (1 ms)
[----------] 1 test from PainterTest (1 ms total)

[----------] Global test environment tear-down
[==========] 1 test from 1 test suite ran. (1 ms total)
[  PASSED  ] 0 tests.
[  FAILED  ] 1 test, listed below:
[  FAILED  ] PainterTest.CanDrawSomething

 1 FAILED TEST
Quarra
  • 2,527
  • 1
  • 19
  • 27
preetam
  • 1,451
  • 1
  • 17
  • 43
  • 1
    I suggest to have a look at [How to create a Minimal, Reproducible Example](https://stackoverflow.com/help/minimal-reproducible-example). I also suggest to revise your question's tags; e.g. how's `tdd` related to this problem? Possibly you want to include the ``c++`` tag? – Ivo Mori Jun 11 '20 at 05:12
  • The example is minimal. Its not big by any means. The output from execution is the one that takes up most of the space. It is relevant though. – preetam Jun 11 '20 at 06:35

1 Answers1

0

You define the expectation on the original turtle mock, but after the first exception you delete and re-create the mock. After that, the new mock has no expectations defined on it and as such all calls to it are reported as uninteresting.

VladLosev
  • 7,296
  • 2
  • 35
  • 46
  • Yes. But how do you test this and address the issue. Turtle is a third party library and as such you cannot change signatures of functions. – preetam Jun 11 '20 at 18:45
  • The simplest course of action is to avoid destroying and re-creating your turtle object repeatedly when you catch the exception. If that's not possible, you can modify your Painter class to inject a factory for Turtle objects and during tests, inject a factory producing already configured mocks - each one configured for a single call. – VladLosev Jun 13 '20 at 21:45