You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在GMOCK中为多参数方法Mock并抛出异常?

问题:Mock Handler::Foo 方法并抛出异常时参数匹配错误

我尝试Mock Handler::Foo 方法,使其抛出异常,该方法接收两个参数:SomeStruct 和 SomeClass。其中SomeStruct是在Source::Bar中动态创建的,SomeClass则从外部传入。

我使用了MATCHER,但它返回单个对象,与Foo所需的两个参数不匹配,因此出现如下错误:

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
}

是否有办法正确Mock Handler::Foo使其抛出异常?

完整代码示例:

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

解决方案

问题核心是MATCHER_P2的使用逻辑错误:MATCHER_P2是用来匹配单个参数的(参数为arg),你试图用它同时匹配Foo的两个参数,不符合Google Mock的规则。以下是几种正确的实现方式:

方法1:使用内置匹配器直接匹配参数

Google Mock提供了Eq()匹配器,只要参数类型支持==运算符即可使用。首先给SomeStruct和SomeClass添加默认的相等运算符:

struct SomeStruct 
{
    int a;
    bool operator==(const SomeStruct& other) const = default;
};

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

然后修改EXPECT_CALL,同时使用Throw内置动作(无需自定义ACTION):

EXPECT_CALL(*mockHandler, Foo(Eq(someStruct), Eq(someClass)))
    .Times(1)
    .WillOnce(Throw(std::invalid_argument("Some exception thrown!")));

注:单次调用场景用WillOnce比WillRepeatedly更合适。

方法2:用With()结合Lambda校验多参数

如果需要自定义复杂的参数校验逻辑,可通过With()传入Lambda同时校验两个参数:

EXPECT_CALL(*mockHandler, Foo(_, _))
    .Times(1)
    .With([&](const SomeStruct& s, const SomeClass& c) {
        return s.a == someStruct.a && c == someClass;
    })
    .WillOnce(Throw(std::invalid_argument("Some exception thrown!")));

_表示匹配任意参数,Lambda中可自由编写校验逻辑。

方法3:为单个参数分别定义MATCHER

如果坚持使用自定义MATCHER,需要为每个参数单独编写匹配器:

// 匹配SomeStruct的自定义MATCHER
MATCHER_P(MatchStruct, expected, "") {
    return arg.a == expected.a;
}

// 匹配SomeClass的自定义MATCHER
MATCHER_P(MatchClass, expected, "") {
    return arg == expected;
}

调用时分别传入对应参数的匹配器:

EXPECT_CALL(*mockHandler, Foo(MatchStruct(someStruct), MatchClass(someClass)))
    .Times(1)
    .WillOnce(Throw(std::invalid_argument("Some exception thrown!")));

最终可运行测试代码

#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <memory>
#include <stdexcept>

struct SomeStruct 
{
    int a;
    bool operator==(const SomeStruct& other) const = default;
};

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

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));
};

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

    EXPECT_CALL(*mockHandler, Foo(Eq(someStruct), Eq(someClass)))
                .Times(1)
                .WillOnce(Throw(std::invalid_argument("Some exception thrown!")));

    Source source(mockHandler);
    EXPECT_THROW(source.Bar(someClass), std::invalid_argument);
}

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

内容的提问来源于stack exchange,提问作者xyf

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.10 18:15:36