单元测试工具GTest/Gmock(二)

2020-07-01  本文已影响0人  wayyyy

接前文。

Gmock是google开发的一套辅助测试的工具,它往往和GTest结合在一起使用。在实际工作中,一个人不可能完成整条线的开发工作。于是我们会在约定接口的前提下,各自完成各自的模块。自己的模块开发完之后,我们需要自测。但是这个时候别人的模块可能还没完成,那么我们就需要模拟约定的接口进行自测。Gmock就是一个强大的模拟接口的工具。

class User
{
public:
    User(){};
    ~User(){};
public:
    // 登录
    virtual bool login(const std::string &username, const std::string &password) = 0;
    // 支付
    virtual bool pay(int money) = 0;
    // 是否登录
    virtual bool online() = 0;
};

// 业务模块要让用户登录,并发起支付行为。
class Biz
{
public:
    void setUser(User *user)
    {
        user_ = user;
    }

    std::string pay(const std::string &username, const std::string &password, int money)
    {
        std::string ret;
        if (!user_)
        {
            ret = "pointer is null.";
            return ret;
        }

        if (!user_->online())
        {
            ret = "logout status. ";
            // 尚未登录,要求登录
            if (!user_->login(username, password))
            {
                // 登录失败
                ret += "login error. ";
                return ret;
            }
            else
            {
                // 登录成功
                ret += "login success. ";
            }
        }
        else
        {
            ret = "login status. ";
        }

        if (!user_->pay(money))
        {
            ret += "pay error. ";
        }
        else
        {
            ret += "pay success. ";
        }

        return ret;
    }

private:
    User *user_;
};

这段代码逻辑就是先看看用户登录了没,如果没有登录则要求用户登录。如果登录失败,则直接返回;如果登录成功,则执行支付行为。最后将流程的状态输出。

那么怎么使用Gmock呢。
第一步:需要Mock接口类

class MockUser : public User
{
public:
    MOCK_METHOD0(online, bool());
    MOCK_METHOD2(login, bool(const std::string &, const std::string &));
    MOCK_METHOD1(pay, bool(int));
};

MOCK_METHOD后跟一个数字,该数字表明需要mock的函数有几个参数。
MOCK_METHOD系列宏的第一个参数是函数名,第二个参数是函数指针的类型。

第二步:我们就可以设计测试场景了。在设计场景之前,我们先看一些Gmock的方法。

EXPECT_CALL(mock_object, Method(argument-matchers))
       .With(multi-argument-matchers)
       .Times(cardinality)
       .InSequence(sequences)
       .After(expectations)
       .WillOnce(action)
       .WillRepeatedly(action)
       .RetiresOnSaturation();

where all clauses are optional, and .InSequence()/.After()/
.WillOnce() can appear any number of times.

现在模拟正常的流程:

TEST(MyTest, PayTest)
{
    MockUser test_user;

    EXPECT_CALL(test_user, online()).WillOnce(testing::Return(false));
    EXPECT_CALL(test_user, login(testing::_, testing::_)).WillRepeatedly(testing::Return(true));
    EXPECT_CALL(test_user, pay(testing::_)).WillOnce(testing::Return(true));

    Biz biz;
    biz.setUser(&test_user);
    std::string pay_result1 = biz.pay("admin", "123", 100);
    cout << pay_result1 << endl;  // 
}

EXPECT_CALL(test_user, online()).WillOnce(testing::Return(false));表示调用online方法返回true
EXPECT_CALL(test_user, login(testing::_, testing::_)).WillRepeatedly(testing::Return(true));表示调用login方法一直返回true,这里testing::_通配符,表示对任何输入参数都按之后要求执行。
EXPECT_CALL(test_user, pay(testing::_)).WillOnce(testing::Return(true));表示调用pay返回true。
编译:

g++ -o test mock1.cpp -lgmock -lgtest_main -lpthread

输出:


image.png

输出结果,表明我们完全模拟出了业务代码种正常支付逻辑,用户没有登录->用户成功登录->支付成功。

参考资料

  1. https://cloud.tencent.com/developer/article/1383727
  2. https://www.cnblogs.com/welkinwalker/archive/2011/11/29/2267225.html
上一篇 下一篇

猜你喜欢

热点阅读