代码之家  ›  专栏  ›  技术社区  ›  pptaszni

如何仅为一个expect调用重写default on_call操作并稍后返回默认操作

  •  5
  • pptaszni  · 技术社区  · 7 年前

    我想测试我的系统的方法,它的返回值部分依赖于对某种连接接口的调用的返回值。在大多数情况下,我希望 IConnection 返回 true 任何形式的召唤 open(_, _) 方法。除了一种情况,当我显式测试连接失败的条件时。

    例子:

    /*
     * Some kind of network interface with method `open`
     */
    class IConnection {
    public:
        IConnection() = default;
        virtual ~IConnection() = default;
        virtual bool open(const std::string& address, int port) = 0;
    };
    
    class ConnectionMock: public IConnection {
    public:
        MOCK_METHOD2(open, bool(const std::string& address, int port));
    };
    
    class MySystem {
    public:
        MySystem() = delete;
        MySystem(std::shared_ptr<IConnection> connection): connection_(connection) {}
        bool doSth() {
            /*
             * Do some things, but fail if connection fails
             */
            bool connectionStatus = connection_->open("127.0.0.1", 6969);
            if (!connectionStatus) {
                return false;
            }
            // do other things
            return true;
        }
    private:
        std::shared_ptr<IConnection> connection_;
    };
    
    TEST(MySystemShould, returnFalseIfFailedToOpenConnectionAndTrueIfSucceeded) {
        auto connectionMock = std::make_shared<NiceMock<ConnectionMock> >();
        ON_CALL(*connectionMock, open(_, _)).WillByDefault(Return(true));
        MySystem system(connectionMock);
        // if I don't specify Times test fill fail, because WillOnce automatically sets Times(1)
        EXPECT_CALL(*connectionMock, open(_, _)).Times(AnyNumber()).WillOnce(Return(false));
        /*
         * Commented code below is not a good solution - after expectation retires
         * the test will fail upon subsequent calls
         */
        //EXPECT_CALL(*connectionMock, open(_, _)).WillOnce(Return(false)).RetiresOnSaturation();
        ASSERT_FALSE(system.doSth());
        /*
         * Code bellow allows me to avoid the warning
         */
        //EXPECT_CALL(*connectionMock, open(_, _)).WillRepeatedly(Return(true));
        ASSERT_TRUE(system.doSth());
    }
    

    我目前的解决方案的问题是 EXPECT_CALL 即使gmock返回到 ON_CALL ,以后每次调用 打开(uu,) 导致以下警告:

    GMOCK WARNING:
    /whatever.cpp:105: Actions ran out in EXPECT_CALL(*connectionMock, open(_, _))...
    Called 2 times, but only 1 WillOnce() is specified - taking default action specified at:
    /whatever.cpp:103:
    

    即使我在用 NiceMock 是的。我可以通过指定 期待您的来电 具有 WillRepeatedly(Return(true)) ,但这是我在 随叫随到 是的。

    我想知道,如何重写 随叫随到 只需要一个电话 IConnection::open ,然后返回默认值,而不会导致gmock打印警告。完美的解决方案类似于:

    EXPECT_CALL(*connectionMock, open(_, _)).WillOnce(Return(false)).DisableExpectationAfterSaturation();
    

    但它不存在。 RetiresOnSaturation 无法按我所希望的方式工作,因为它在饱和后无法通过测试(与指定的操作不匹配 随叫随到 )中。

    1 回复  |  直到 7 年前
        1
  •  3
  •   Mike van Dyke    7 年前

    编辑2
    这个 DoDefault() -功能与问题中的问题很接近。它指定 EXPECT_CALL 应返回到由指定的默认操作 ON_CALL 以下内容:

    using ::testing::DoDefault;
    
    // Default action
    ON_CALL(*connectionMock, open(_, _)).WillByDefault(Return(true));
    
    // returns true once and then goes back to the default action
    EXPECT_CALL(*connectionMock, open(_, _)
      .WillOnce(Return(false))
      .WillRepeatedly(DoDefault());
    

    初步答复

    如果 IConnection::open 取决于您可以指定的参数 随叫随到 两次,但参数不同(或者更确切地说,参数不是占位符):

    ON_CALL(*connectionMock, open(_, _)).WillByDefault(Return(true));
    ON_CALL(*connectionMock, open("BAD_ADDRESS", 20)).WillByDefault(Return(false));
    

    所以不管什么时候 open 将用参数“bad_address”和20调用,它将返回false,否则返回true。

    下面是一个简单的例子:

    using ::testing::_;
    using ::testing::AnyNumber;
    using ::testing::Return;
    
    class A {
     public:
      virtual bool bla(int a) = 0;
    };
    
    class MOCKA : public A {
     public:
      MOCK_METHOD1(bla, bool(int));
    };
    
    TEST(ABC, aBABA) {
      MOCKA a;
      ON_CALL(a, bla(_)).WillByDefault(Return(false));
      ON_CALL(a, bla(1)).WillByDefault(Return(true));
    
      EXPECT_CALL(a, bla(_)).Times(AnyNumber());
    
      EXPECT_TRUE(a.bla(1));
      EXPECT_TRUE(a.bla(1));
      EXPECT_TRUE(a.bla(1));
      EXPECT_FALSE(a.bla(2));
      EXPECT_FALSE(a.bla(3));
      EXPECT_FALSE(a.bla(4));
    }
    

    编辑1 我想现在我明白了这个问题,如果我明白了,那么解决方法就非常简单:

    EXPECT_CALL(*connectionMock, open(_, _))
          .Times(AnyNumber())
          .WillOnce(Return(true))
          .WillRepeatedly(Return(false));
    

    什么时候? ConnectionMock::open 将在内部调用 MySystem::doSth 它一回来 true 然后总是回来 false 不管争论是什么。在这种情况下,您也不需要指定 随叫随到 是的。或者你真的需要用 随叫随到 而不是 期待您的来电 是吗?

    推荐文章