xyf
xyf

Reputation: 714

Mocking a method's parameter in unit test

I am trying to mock a method Foo::TestTime that takes a parameter and is called within a separate function. The problem I'm having is the matching of the parameter values.

Bar::Run() is invoked by the user in the unit test which generates the time and passes it to Foo::TestTime, which I need to mock from unit test.

struct Foo
{
    virtual void TestTime(long time) {}
};

struct FooMock : public Foo
{
    MOCK_METHOD(void, TestTime, (long), (override));
};

class Bar
{   
    long time{0};
    Foo _foo;

    public:
    Bar(Foo foo) : _foo(foo) {}
    void Run() 
    {
       time = GetTime();
       _foo.TestTime(time);     // mock this function     
    }
};

How can I match the time between Bar::Run() and in unit test MOCK_METHOD? Is Matcher the way to go?

Full codesample

long GetTime()
{
    return std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count();
}

struct Foo
{
    virtual void TestTime(long time)
    {

    }
};

struct FooMock : public Foo
{
    MOCK_METHOD(void, TestTime, (long), (override));
};

class Bar
{   
    long time{0};
    Foo _foo;

    public:
    Bar(Foo foo) : _foo(foo) {}
    void Run() 
    {
       time = GetTime();
       _foo.TestTime(time);     // mock this function     
    }
};

TEST(UtClass, Test)
{
    Foo foo;
    FooMock fooMock;

    long time = GetTime();

    EXPECT_CALL(fooMock, TestTime(time)).WillOnce(testing::Return());

    Bar bar{foo};
    bar.Run();
}

Upvotes: 0

Views: 481

Answers (1)

Joe
Joe

Reputation: 36

If the point of the test is to make sure that TestTime() is getting called, then I wouldn't worry about matching the actual value of the time parameter at all. Instead you could write you test like this.

    EXPECT_CALL(fooMock, TestTime(_));

The _ (or more specifically testing::_) will match any input given to it.

If you really do need to test what the value of time was, you can either Mock the GetTime() call or create a fake GetTime() that allows the test to decide what is returned.

Edit: I looked at the example code you had posted. The reason the test was failing was because the mock object was getting copied when you passed it into Bar's constructor. You were also passing in the foo object. Instead it should pass in the fooMock object.

Updated example link: https://godbolt.org/z/fY5c9qhTf Though I still wouldn't recommend trying to match the time value in the test. Doing so will result in a potentially flaky test.

Upvotes: 1

Related Questions