全局检查模拟中的值

Globally check value in mock

我有一个模拟 API 包装器。

class MockApiWrapper : public ApiWrapper {
    public:
        MockNrfWrapper();
        virtual ~MockNrfWrapper();
        MOCK_METHOD1(api_do, void(int param));
};

让我们假设 api_do 不应该用 param = 0 调用。因为我使用这个模拟 "everywhere",所以我想在对 api_do 的每个调用中附加一个 assertion/expect。示例:

void MyClass::InvalidCallsToApi(void) {
    // api->api_do(0);  // Fails "global assert"
    // api->api_do(1);  // Fails by specific test
    api->api_do(2);     // Valid call
}
TEST(MyTestCase, FirstTest) {
    // Mock always checks that api_do is not called
    // with argument of 0
    EXPECT_CALL(api, api_do(Ne(1));
    uut->InvalidCallsToApi();
}

我尝试在构造函数中使用 ON_CALLInvoke 来执行此操作,但它要么被测试中添加的 EXPECT 覆盖,要么出现编译错误(无法执行 ASSERT或调用调用中的 EXPECT)。

我希望我的问题陈述清楚。在此先感谢您的任何意见!

我想出了一个解决方案,它不是最好的,但可以接受 IMO。

代码:

struct BInterface {
    virtual void foo(int) = 0;
};

struct BMock : public BInterface {
    MOCK_METHOD1(foo, void(int));
    BMock() {
        ON_CALL(*this, foo(0))
                .WillByDefault(::testing::InvokeWithoutArgs([](){ADD_FAILURE() << "This function can't be called with argument 0";}));
    }
};

void testedMethod(int a) {
    BInterface* myB = new BMock;
    myB->foo(a);
    delete myB;
}

TEST(myTest, okCase) {
    testedMethod(1);
}

TEST(myTest, notOkCase) {
    testedMethod(0);
}

解释:
我们为 BMock 添加一个默认操作,用于每次调用带有参数 0foo 方法。
在此操作中,我们调用 lambda,它使用 GTest 宏 ADD_FAILURE() 生成非致命失败 - 相当于 EXPECT_* 宏。您可以使用 FAIL() 代替 ASSERT_* 宏中的致命故障。

我们在 mock 的构造函数中使用了 ON_CALL 宏,这样可以避免使用其他所有 mock 对象调用它。

限制:
例如,同样的技巧不适用于 EXPECT_CALL - 我不知道 GMock 实现,但我假设 EXPECT_CALL 需要一个完全初始化的对象。

使用匹配器接受 0 的调用仍然会通过(即 EXPECT_CALL(myB, foo(::testing::_));,但在所有其他 GMock 期望中都是这种情况。当遇到新的期望时,GMock 总是会掩盖旧的期望。你必须以这样一种方式来创建您的期望,即它们不会覆盖以前的期望。
.RetiresOnSaturation() 添加到您的所有 EXPECT_CALL 将确保在他们不感兴趣时​​将呼叫转发到默认操作(由 ON_CALL 设置)。
当有多个不允许的值时,自定义匹配器会很有帮助。

MATCHER(IsValidApiArg, ""){return arg == 0 || arg == 1;}

ON_CALL(*this, api_foo(!IsValidApiArg)
        .WillByDefault(::testing::InvokeWithoutArgs([](){ADD_FAILURE();}));

EXPECT_CALL(myMock, api_foo(IsValidApiArg)); 

注意:我仍然无法相信 GMock 不提供简单地生成故障的默认操作。也许你可以在文档的深处找到更合适的东西。
您还可以为此创建一个自定义操作,以避免所有 Invoke 和 lambdas.