Home > OS >  Matching multiple objects in a MOCK_METHOD
Matching multiple objects in a MOCK_METHOD

Time:11-27

I am trying to mock a method Handler::Foo to throw an exception that takes in two objects as parameters i.e SomeStruct, SomeClass. The former is created Source::Bar on the fly whereas SomeClass is passed from main.

I used MATCHER but it returns a single object which doesn't match with what Foo expects (2 parameters), hence the error.

no matching function for call to 'MockHandler::gmock_Foo(MatchMatcherP2<SomeStruct, SomeClass>)'

ACTION(MyThrowException)    
{
  throw std::invalid_argument("Some exception thrown!");
}

TEST(UtClass, TestSourceBar)
{
    auto mockHandler = std::make_shared<MockHandler>();
    SomeStruct someStruct = {.a = 10};
    SomeClass someClass;

    EXPECT_CALL(*mockHandler, Foo(Match(someStruct, someClass)))
                .Times(1)
                .WillRepeatedly(MyThrowException()); // ERROR
}

Is there a way to mock Handler::Foo such that it throws an exception?

Here's a live sample

struct SomeStruct 
{
    int a;
};

class SomeClass 
{
    public:
    // some methods...
};

class Handler
{
    public:
    virtual void Foo(const SomeStruct&, SomeClass)
    {
        // stuff...
    }
};

class Source
{
    std::weak_ptr<Handler> _handler;

    public:
    Source(std::weak_ptr<Handler> handler) : _handler(handler) {}

    void Bar(SomeClass someClass)
    { 
        SomeStruct s = {.a = 10};        
        if (auto sp = _handler.lock())
        {
            sp->Foo(s, someClass);   // simulate this call
        }
    }
};

class MockHandler : public Handler
{
    public:
    MOCK_METHOD(void, Foo, (const SomeStruct&, SomeClass), (override));
};

MATCHER_P2(Match, someStruct, someClass, "")
{
    return arg.a == someStruct.a && arg.someClass == someClass;
}

ACTION(MyThrowException)    
{
  throw std::invalid_argument("Some exception thrown!");
}
  
TEST(UtClass, TestSourceBar)
{
    auto mockHandler = std::make_shared<MockHandler>();
    SomeStruct someStruct = {.a = 10};
    SomeClass someClass;

    EXPECT_CALL(*mockHandler, Foo(Match(someStruct, someClass)))
                .Times(1)
                .WillRepeatedly(MyThrowException()); // ERROR

    
    Source source(mockHandler);
    source.Bar(someClass); // should throw an exception...
}

CodePudding user response:

The matcher is meant to test some conditions for a single argument, so you would need to use a separate matcher for each one.

It's not really clear what you want to test here, but one way of doing what your example shows would be:

class SomeClass 
{
    public:
    bool operator==(const SomeClass &) const = default;
    // some methods...
};

MATCHER_P(MatchSomeStruct, someStruct, "")
{
    return arg.a == someStruct.a;
}

MATCHER_P(MatchSomeClass, someClass, "")
{
    return arg == someClass;
}
  
TEST(UtClass, TestSourceBar)
{
    auto mockHandler = std::make_shared<MockHandler>();
    SomeStruct someStruct = {.a = 10};
    SomeClass someClass;

    EXPECT_CALL(*mockHandler, Foo(MatchSomeStruct(someStruct), MatchSomeClass(someClass)))
                .Times(1)
                .WillRepeatedly(MyThrowException());

This will of course check the two parameters separately. If you need to check the two parameters as a whole then you could look into adding a With() clause.

  • Related