简体   繁体   中英

How to Mock A Method(non-virtual) To Return Particular Value Using GMock in C++?

My Issue is I want to Mock an Static Non-Virtual Method to return true, which is eventually return false.

I have Static Method eg:

class SomeClass{ 
    public:
    static bool SomeClass::DoAction() {
        // do some Actions
    };
};

I wanted to return always true during mocks, but it by default return false, Are there anyways to Mock

I have Tried the following approach to check the on call value and find out it cause false.

class MockSomeClass : public SomeClass {
public:
    MockSomeClass() {
        ON_CALL(this, DoAction).WillByDefault(testing::Return(true));
    }
    virtual ~MockSomeClass(){};
    MOCK_METHODO(DoAction, bool());

As the Mock is used to leave the functions, are there any ways to return a specific value for the function, or replace the return value to true and continue operation in testing using gmock and gtest in C++. consider example below Eg:

  FunctionA(){
      if (SomeClass::DoAction()){
          // do Actions - I wanted to pass the call do the actions.
      } 
  };

here I want to test the action in the if true case, are there any ways to do above methods testable without changing any underlying codes.

I have tried different approaches present in the method still i didn't able to get an exact solutions. https://github.com/google/googletest/tree/master/googlemock/docs

  1. Using Default Value

     using ::testing::DefaultValue; DefaultValue<bool>::Set(true); // call the mock methods DefaultValue<bool>::Clear(); 
  2. Using Invoke, this doesn't work since the static method is non void.

Are there any solutions except the above mention methods.

I wanted to just write a comment, but it would be too long, therefore here is the answer. If you cannot change your production code at all, don't read further, it is simply impossible to test it (at least it is impossible to alter the behavior of calls to SomeClass::DoAction() ). If you can change the code a little bit, and if you wish to make it more testable and flexible, define the interface responsible for calls to the static (or global) functions and pass it to your system's constructor.

class SomeClass{ 
public:
    static bool DoAction() {
        std::cout << "Call to SomeClass::DoAction" << std::endl;
        return false;
    };
};

// you absolutely need this, otherwise your code will be strongly dependent on the real SomeClass implementation
class ISomeClassInterface {
public:
    virtual ~ISomeClassInterface() = default;
    virtual bool DoAction() = 0;
};

/*
 * use it in the production
 * you can even make it a default constructor parameter to simplify objects
 * constructions outside testing env
 */
class RealSomeClassInterface: public ISomeClassInterface {
public:
    ~RealSomeClassInterface() override = default;
    bool DoAction() override {
        // call to real SomeClass
        return SomeClass::DoAction();
    }
};

class MockSomeClassInterface: public ISomeClassInterface {
public:
    ~MockSomeClassInterface() override = default;
      MOCK_METHOD0(DoAction, bool());
};

class System {
public:
    System(std::shared_ptr<ISomeClassInterface> interface): interface_(interface) {}
    // let's imagine this is your code that is dependent on the DoAction return value
    bool DoAction() {
        return interface_->DoAction();
    }
private:
    std::shared_ptr<ISomeClassInterface> interface_;
};

TEST(xxx, yyy) {
    auto realInterface = std::make_shared<RealSomeClassInterface>();
    auto mockInterface =  std::make_shared<MockSomeClassInterface>();
    ON_CALL(*mockInterface, DoAction()).WillByDefault(Return(true));
    System systemWithRealInterface(realInterface);
    System systemWithMockInterface(mockInterface);
    std::cout << "System::DoAction returns: " << systemWithRealInterface.DoAction() << std::endl;
    std::cout << "System::DoAction returns: " << systemWithMockInterface.DoAction() << std::endl;
}

The test output should look like this:

[ RUN      ] xxx.yyy
Call to SomeClass::DoAction
System::DoAction returns: 0

GMOCK WARNING:
Uninteresting mock function call - taking default action specified at:
whatever.cpp:76:
    Function call: DoAction()
          Returns: true
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/CookBook.md#knowing-when-to-expect for details.

System::DoAction returns: 1
[       OK ] xxx.yyy (0 ms)

You can also do the hack using C++ templates

    template <class T>
    bool DoAction() { return T::DoAction(); }

but I don't like and I don't recommend this solution.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM