sinojelly / mockcpp

Two C/C++ testing tools, mockcpp and testngpp.
Apache License 2.0
67 stars 42 forks source link

怎么取消指定MOCKER #29

Open lightthgil opened 3 years ago

lightthgil commented 3 years ago

GlobalMockObject::verify(); 或者GlobalMockObject::reset();可以取消所有的MOCKER,但是,如果我想保留一部分MOCKER,只取消另一部分MOCKER,需要怎么做?

sinojelly commented 3 years ago

你说的是 C 函数的mock [ 用 MOCKER(func) ] 还是 C++虚函数的mock [ 用 MOCK_METHOD(mocker, method) ]。 如果是前者,可能多个 C 函数,都是统一通过 GlobalMockObject操作的,暂时可能不好单个操作。 如果是后者,可能你针对一个mock对象 mocker,可以单独进行操作。但是一个 mocker 有多个 method 的mock,要取消其中某一个,可能没有现成的方式支持。

我还没详细去看怎么支持单个 mocker 的取消。 基于已有的特性,每个mockder 可以指定 id, 也许有可能通过 指定id的方式,取消一个 mocker。

lightthgil commented 3 years ago

无论是C函数使用GlobalMockObject::reset();还是C++虚函数使用mock_class_instance.reset(),最终都会调用到 https://github.com/sinojelly/mockcpp/blob/826f71bc7ba4e8bed4a1786cf4f01b6619096e55/src/ChainableMockMethodContainer.cpp#L85-L95 而resetMethod可以删除特定的mock https://github.com/sinojelly/mockcpp/blob/826f71bc7ba4e8bed4a1786cf4f01b6619096e55/src/ChainableMockMethodContainer.cpp#L71-L82 是否可以将resetMethod通过某种方式暴露出来

sinojelly commented 3 years ago

嗯,大概是这个思路。但是要让使用者,可以方便的 reset 指定的mocker 才行。 从你贴的代码来看, ChainableMockMethodContainerImpl::ValueType 这样的类型,用户是不好用的。

所以我说 reset 指定的 mocker, 得先有个办法指定 mocker,然后reset 它。 我能想到的是 mocker 可以指定 id, 所以如果能把 mocker 指定的 id, 与 reset 实现联系起来。 用户就可以用下面方式reset指定的mocker了。 mocker.reset(id)

darren-zhk commented 3 years ago

老哥这个项目还在维护吗 关于reset这个。可否在一类关键字(stubs)后扩展一个reset?

sinojelly commented 3 years ago

老哥这个项目还在维护吗 关于reset这个。可否在一类关键字(stubs)后扩展一个reset?

你说的 .stubs之后,可以.reset 吗? 可能达不到用完一个mocker就取消的效果哦。

有需求,可以在这个issue上+1。还可以在评论中写一下具体场景,为什么需要这个特性。

当然也欢迎提出方案,甚至实现这个特性。

lightthgil commented 2 years ago

老哥这个项目还在维护吗 关于reset这个。可否在一类关键字(stubs)后扩展一个reset?

你说的 .stubs之后,可以.reset 吗? 可能达不到用完一个mocker就取消的效果哦。

有需求,可以在这个issue上+1。还可以在评论中写一下具体场景,为什么需要这个特性。

当然也欢迎提出方案,甚至实现这个特性。

我这边还有这个需求。 大致的应用场景是,由高级开发人员构造一个复杂的场景,模拟真实的环境,里面会有MOCK。然后低级别开发人员基于该场景去写测试用例。测试用例中可能会自己MOCK有些函数,然后自己在测试用例的结尾unmock掉。

举个栗子:

class Scenes_base : public testing::Test {
  public:
    Scenes_base(){};
    ~Scenes_base(){};
    virtual void SetUp() override;
    virtual void TearDown() override;
};
void Scenes_base::SetUp()
{
    // do something
    MOCKER(func1).stubs().will(invoke(fake_func1));
    MOCKER(func2).stubs().will(returnValue(0));
}
void Scenes_base::TearDown()
{
    GlobalMockObject::verify();
}

class Scenes_online : public Scenes_base {
  public:
    Scenes_online(){};
    virtual ~Scenes_online(){};
    virtual void SetUp() override;
    virtual void TearDown() override;;
};

void Scenes_online::SetUp()
{
    Scenes_base::SetUp();
    // do something
}

void Scenes_online::TearDown()
{
    Scenes_base::TearDown();
}

TEST_F(Scenes_online, return_1_offline_when_xxx)
{
    MOCKER(recv_online_state).stubs().will(returnValue(false)).id("recv_online_state_return_false");
    // do something

    EXPECT_NE(get_online_state(), false);

    MOCKER(recv_online_state).id("recv_online_state_return_false").reset();    //期望这里取消桩
}

TEST_F(Scenes_online, return_1_online_when_xxx)
{
    MOCKER(recv_online_state).stubs().will(returnValue(true)).id("recv_online_state_return_true");
    // do something

    EXPECT_NE(get_online_state(), true);

    MOCKER(recv_online_state).id("recv_online_state_return_true").reset();    //期望这里取消桩
}

实际的应用会比这个例子复杂。但是大致是这个意思,在Scenes_online的几个测试用例中,希望复用基础场景Scene_base构建的环境,测试不同的功能,每个测试可能会有MOCK,如上述两个测试用例Scenes_online.return_1_offline_when_xxxScenes_online.return_1_true_when_xxx,但是每个测试用例跑完后,需要UNMOCK掉自己测试用例中的MOCKER,防止影响下一个测试用例。如果用GlobalMockObject::verify()或者GlobalMockObject::reset(),则同时会unmock掉基础场景Scene_base中的MOCKER,导致场景不可用,所以希望能仅unmock掉自己测试用例的MOCKER

darren-zhk commented 2 years ago

应用场景:

老哥这个项目还在维护吗 关于reset这个。可否在一类关键字(stubs)后扩展一个reset?

你说的 .stubs之后,可以.reset 吗? 可能达不到用完一个mocker就取消的效果哦。 有需求,可以在这个issue上+1。还可以在评论中写一下具体场景,为什么需要这个特性。 当然也欢迎提出方案,甚至实现这个特性。

我这边还有这个需求。 大致的应用场景是,由高级开发人员构造一个复杂的场景,模拟真实的环境,里面会有MOCK。然后低级别开发人员基于该场景去写测试用例。测试用例中可能会自己MOCK有些函数,然后自己在测试用例的结尾unmock掉。

举个栗子:

class Scenes_base : public testing::Test {
  public:
    Scenes_base(){};
    ~Scenes_base(){};
    virtual void SetUp() override;
    virtual void TearDown() override;
};
void Scenes_base::SetUp()
{
    // do something
    MOCKER(func1).stubs().will(invoke(fake_func1));
    MOCKER(func2).stubs().will(returnValue(0));
}
void Scenes_base::TearDown()
{
    GlobalMockObject::verify();
}

class Scenes_online : public Scenes_base {
  public:
    Scenes_online(){};
    virtual ~Scenes_online(){};
    virtual void SetUp() override;
    virtual void TearDown() override;;
};

void Scenes_online::SetUp()
{
    Scenes_base::SetUp();
    // do something
}

void Scenes_online::TearDown()
{
    Scenes_base::TearDown();
}

TEST_F(Scenes_online, return_1_offline_when_xxx)
{
    MOCKER(recv_online_state).stubs().will(returnValue(false)).id("recv_online_state_return_false");
    // do something

    EXPECT_NE(get_online_state(), false);

    MOCKER(recv_online_state).id("recv_online_state_return_false").reset();    //期望这里取消桩
}

TEST_F(Scenes_online, return_1_online_when_xxx)
{
    MOCKER(recv_online_state).stubs().will(returnValue(true)).id("recv_online_state_return_true");
    // do something

    EXPECT_NE(get_online_state(), true);

    MOCKER(recv_online_state).id("recv_online_state_return_true").reset();    //期望这里取消桩
}

实际的应用会比这个例子复杂。但是大致是这个意思,在Scenes_online的几个测试用例中,希望复用基础场景Scene_base构建的环境,测试不同的功能,每个测试可能会有MOCK,如上述两个测试用例Scenes_online.return_1_offline_when_xxxScenes_online.return_1_true_when_xxx,但是每个测试用例跑完后,需要UNMOCK掉自己测试用例中的MOCKER,防止影响下一个测试用例。如果用GlobalMockObject::verify()或者GlobalMockObject::reset(),则同时会unmock掉基础场景Scene_base中的MOCKER,导致场景不可用,所以希望能仅unmock掉自己测试用例的MOCKER

看了下实列我觉得取消的桩的方式略显复杂 希望的方式如下:

TEST_F(Scenes_online, return_1_online_when_xxx)
{
    MOCKER(recv_online_state).stubs().will(returnValue(true));
    // do something

    EXPECT_NE(get_online_state(), true);

    MOCKER(recv_online_state).reset();    //期望这里取消桩
}