如何使用GoogleMock使用模拟功能填充结构?

发布于 2025-02-08 06:37:55 字数 1237 浏览 3 评论 0原文

我有一个函数:

    int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);

人页面告诉我“ 参数addr是sockAddr结构的指针。此结构用对等插座的地址填充,如通信层所知。“因此,我将使用以下方式调用以下功能:

    struct sockaddr_storage clientAddr;
    struct sockaddr* sa{(sockaddr*)&clientAddr};
    clientLen = sizeof(clientAddr);;

    accept_sock = accept(listen_sock, (struct sockaddr*)&clientAddr, &clientLen);

使用Mocking 接受我想填充clientAddr使用:

    struct sockaddr_in* sa_in{(sockaddr_in*)&clientAddr};
    sa_in->sin_family = AF_INET;
    sa_in->sin_port = htons(50000);
    inet_pton(AF_INET, "192.168.1.2", &sa_in->sin_addr);

To return a mocked pointer to a filled structure I would use:

    EXPECT_CALL(mocked_sys_socket, accept(listen_sock, _, Pointee(clientLen)))
        .WillOnce(DoAll(SetArgPointee<1>(*sa), Return(accept_sock)));

但这不是我在这里需要的。 clientAddr结构已经给出。

什么动作而不是setArgpointee&lt;(*sa)我必须用来返回提供的结构client> clientaDdr

I have a function for example:

    int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);

The man page tell me "The argument addr is a pointer to a sockaddr structure. This structure is filled in with the address of the peer socket, as known to the communications layer." So I would call the function with:

    struct sockaddr_storage clientAddr;
    struct sockaddr* sa{(sockaddr*)&clientAddr};
    clientLen = sizeof(clientAddr);;

    accept_sock = accept(listen_sock, (struct sockaddr*)&clientAddr, &clientLen);

With mocking accept I would like to fill clientAddr with:

    struct sockaddr_in* sa_in{(sockaddr_in*)&clientAddr};
    sa_in->sin_family = AF_INET;
    sa_in->sin_port = htons(50000);
    inet_pton(AF_INET, "192.168.1.2", &sa_in->sin_addr);

To return a mocked pointer to a filled structure I would use:

    EXPECT_CALL(mocked_sys_socket, accept(listen_sock, _, Pointee(clientLen)))
        .WillOnce(DoAll(SetArgPointee<1>(*sa), Return(accept_sock)));

But that isn't what I need here. The clientAddr structure is already given.

What action instead of SetArgPointee<1>(*sa) I have to use to return with filling the provided structure clientAddr?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

眼中杀气 2025-02-15 06:37:55

iiuc,您希望通过呼叫AcceptAccept的第二个参数,该参数当前是sa_int将设置为sa_next的值。

如果是这样,我可以想到两个选择:

struct sockaddr {
  std::string name;
};

class MockedSysSocket {
 public:
  MOCK_METHOD(int, accept, (int, sockaddr *, socklen_t *addrlen), ());
};

TEST(MockedSysSocketTest, SideEffect1) {
  MockedSysSocket mocked_sys_socket;

  int accept_sock = 1;
  int listen_sock = 2;

  sockaddr sa_in{"initial"};
  sockaddr sa_next{"next"};

  socklen_t clientLen = sizeof(sockaddr);

  EXPECT_CALL(mocked_sys_socket, accept(listen_sock, &sa_in, &clientLen))
      .WillOnce(DoAll(SetArgPointee<1>(sa_next), Return(accept_sock)));

  auto actual = mocked_sys_socket.accept(listen_sock, &sa_in, &clientLen);
  EXPECT_EQ(sa_in.name, sa_next.name);
  EXPECT_EQ(actual, accept_sock);
}

TEST(MockedSysSocketTest, SideEffect2) {
  MockedSysSocket mocked_sys_socket;

  int accept_sock = 1;
  int listen_sock = 2;

  sockaddr sa_in{"initial"};
  sockaddr sa_next{"next"};

  socklen_t clientLen = sizeof(sockaddr);

  EXPECT_CALL(mocked_sys_socket, accept(listen_sock, &sa_in, &clientLen))
      .WillOnce(WithArg<1>(Invoke([&sa_next, accept_sock](sockaddr *in) {
        *in = sa_next;
        return accept_sock;
      })));

  auto actual = mocked_sys_socket.accept(listen_sock, &sa_in, &clientLen);
  EXPECT_EQ(sa_in.name, sa_next.name);
  EXPECT_EQ(actual, accept_sock);
}

实时示例: https://godbolt.org.org.org/z/3h4ffcnd7

IIUC, you want that as a result of a call to accept, the second parameter of accept, which is currently sa_int to be set to the value of sa_next.

If that's the case, I can think of two options:

struct sockaddr {
  std::string name;
};

class MockedSysSocket {
 public:
  MOCK_METHOD(int, accept, (int, sockaddr *, socklen_t *addrlen), ());
};

TEST(MockedSysSocketTest, SideEffect1) {
  MockedSysSocket mocked_sys_socket;

  int accept_sock = 1;
  int listen_sock = 2;

  sockaddr sa_in{"initial"};
  sockaddr sa_next{"next"};

  socklen_t clientLen = sizeof(sockaddr);

  EXPECT_CALL(mocked_sys_socket, accept(listen_sock, &sa_in, &clientLen))
      .WillOnce(DoAll(SetArgPointee<1>(sa_next), Return(accept_sock)));

  auto actual = mocked_sys_socket.accept(listen_sock, &sa_in, &clientLen);
  EXPECT_EQ(sa_in.name, sa_next.name);
  EXPECT_EQ(actual, accept_sock);
}

TEST(MockedSysSocketTest, SideEffect2) {
  MockedSysSocket mocked_sys_socket;

  int accept_sock = 1;
  int listen_sock = 2;

  sockaddr sa_in{"initial"};
  sockaddr sa_next{"next"};

  socklen_t clientLen = sizeof(sockaddr);

  EXPECT_CALL(mocked_sys_socket, accept(listen_sock, &sa_in, &clientLen))
      .WillOnce(WithArg<1>(Invoke([&sa_next, accept_sock](sockaddr *in) {
        *in = sa_next;
        return accept_sock;
      })));

  auto actual = mocked_sys_socket.accept(listen_sock, &sa_in, &clientLen);
  EXPECT_EQ(sa_in.name, sa_next.name);
  EXPECT_EQ(actual, accept_sock);
}

Live example: https://godbolt.org/z/3h4ffcnd7

写下不归期 2025-02-15 06:37:55

ARI的答案显示了解决方案。这里有一个完整的示例是我现在使用的实现。

#include <sys/socket.h>
#include <arpa/inet.h>
#include "gmock/gmock.h"

using ::testing::_;
using ::testing::DoAll;
using ::testing::Pointee;
using ::testing::Return;
using ::testing::SetArgPointee;

//
class SysSocketInterface {
  public:
    virtual ~SysSocketInterface() {}
    virtual int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen) = 0;
};

// Version to call the real system function.
class RealSysSocket : public SysSocketInterface {
  public:
    virtual ~RealSysSocket() override {}
    int accept(int sockfd, struct sockaddr* addr, socklen_t* addrlen) override {
        return ::accept(sockfd, addr, addrlen);
    }
};

// Version to call the mocked system function.
class MockSysSocket : public SysSocketInterface {
  public:
    virtual ~MockSysSocket() override {}
    MOCK_METHOD(int, accept, (int, struct sockaddr*, socklen_t*), (override));
};

// Polymorphic class
class SysSocket {
    SysSocketInterface* m_syssocket;

  public:
    SysSocket(SysSocketInterface* a_syssocket) : m_syssocket(a_syssocket) {}

    std::string get_addr(int a_listen_sock) {
        struct sockaddr_storage clientAddr;
        struct sockaddr_in* clientAddr_in{(sockaddr_in*)&clientAddr};
        socklen_t socklen = sizeof(sockaddr_storage);

        int accept_sock = m_syssocket->accept(a_listen_sock,
                                              (sockaddr*)&clientAddr, &socklen);
        if (accept_sock == -1) {
            return "";
        }

        char text_addr[INET_ADDRSTRLEN];
        if (inet_ntop(AF_INET, &clientAddr_in->sin_addr, text_addr,
                      sizeof(text_addr)) == nullptr) {
            return "";
        }

        unsigned short int port = ntohs(clientAddr_in->sin_port);
        return std::string(text_addr) + ":" + std::to_string(port);
    }
};

//
TEST(SysSocketTestSuite, call_real_sys_socket_accept) {
    RealSysSocket real_sys_socket;
    // Inject real sys_socket object
    SysSocket sys_socket(&real_sys_socket);

    int listen_sock = 0;

    // Test Unit
    // Listen_sock is not a valid socket
    EXPECT_EQ(sys_socket.get_addr(listen_sock), "");
}

TEST(SysSocketTestSuite, mock_sys_socket_accept) {
    // Provide a socket address
    struct sockaddr_storage clientAddrMock;
    struct sockaddr* sa{(sockaddr*)&clientAddrMock};
    struct sockaddr_in* sa_in{(sockaddr_in*)&clientAddrMock};
    sa_in->sin_family = AF_INET;
    sa_in->sin_port = htons(50000u);
    inet_pton(AF_INET, "192.168.1.2", &sa_in->sin_addr);
    socklen_t socklen = sizeof(sockaddr_storage);

    // Instantiate mocked sys_socket object
    MockSysSocket mock_sys_socket;
    // Inject mocked sys_socket object
    SysSocket sys_socket(&mock_sys_socket);

    int listen_sock = 3;
    int accept_sock = 4;

    EXPECT_CALL(mock_sys_socket, accept(listen_sock, _, Pointee(socklen)))
        .WillOnce(DoAll(SetArgPointee<1>(*sa), Return(accept_sock)));

    // Test Unit
    EXPECT_EQ(sys_socket.get_addr(listen_sock), "192.168.1.2:50000");
}
//-----------------------------------------------------------------------------

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

通过执行测试,我得到了:

[==========] Running 2 tests from 1 test suite.
[----------] Global test environment set-up.
[----------] 2 tests from MockedSysSocketTest
[ RUN      ] MockedSysSocketTest.call_real_sys_socket_accept
[       OK ] MockedSysSocketTest.call_real_sys_socket_accept (0 ms)
[ RUN      ] MockedSysSocketTest.mock_sys_socket_accept
[       OK ] MockedSysSocketTest.mock_sys_socket_accept (0 ms)
[----------] 2 tests from MockedSysSocketTest (0 ms total)

[----------] Global test environment tear-down
[==========] 2 tests from 1 test suite ran. (0 ms total)
[  PASSED  ] 2 tests.

参考:
依赖注入和用GoogleMock模拟的实践示例

The answer of Ari shows the solution. To have a complete example here is the implementation I use now.

#include <sys/socket.h>
#include <arpa/inet.h>
#include "gmock/gmock.h"

using ::testing::_;
using ::testing::DoAll;
using ::testing::Pointee;
using ::testing::Return;
using ::testing::SetArgPointee;

//
class SysSocketInterface {
  public:
    virtual ~SysSocketInterface() {}
    virtual int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen) = 0;
};

// Version to call the real system function.
class RealSysSocket : public SysSocketInterface {
  public:
    virtual ~RealSysSocket() override {}
    int accept(int sockfd, struct sockaddr* addr, socklen_t* addrlen) override {
        return ::accept(sockfd, addr, addrlen);
    }
};

// Version to call the mocked system function.
class MockSysSocket : public SysSocketInterface {
  public:
    virtual ~MockSysSocket() override {}
    MOCK_METHOD(int, accept, (int, struct sockaddr*, socklen_t*), (override));
};

// Polymorphic class
class SysSocket {
    SysSocketInterface* m_syssocket;

  public:
    SysSocket(SysSocketInterface* a_syssocket) : m_syssocket(a_syssocket) {}

    std::string get_addr(int a_listen_sock) {
        struct sockaddr_storage clientAddr;
        struct sockaddr_in* clientAddr_in{(sockaddr_in*)&clientAddr};
        socklen_t socklen = sizeof(sockaddr_storage);

        int accept_sock = m_syssocket->accept(a_listen_sock,
                                              (sockaddr*)&clientAddr, &socklen);
        if (accept_sock == -1) {
            return "";
        }

        char text_addr[INET_ADDRSTRLEN];
        if (inet_ntop(AF_INET, &clientAddr_in->sin_addr, text_addr,
                      sizeof(text_addr)) == nullptr) {
            return "";
        }

        unsigned short int port = ntohs(clientAddr_in->sin_port);
        return std::string(text_addr) + ":" + std::to_string(port);
    }
};

//
TEST(SysSocketTestSuite, call_real_sys_socket_accept) {
    RealSysSocket real_sys_socket;
    // Inject real sys_socket object
    SysSocket sys_socket(&real_sys_socket);

    int listen_sock = 0;

    // Test Unit
    // Listen_sock is not a valid socket
    EXPECT_EQ(sys_socket.get_addr(listen_sock), "");
}

TEST(SysSocketTestSuite, mock_sys_socket_accept) {
    // Provide a socket address
    struct sockaddr_storage clientAddrMock;
    struct sockaddr* sa{(sockaddr*)&clientAddrMock};
    struct sockaddr_in* sa_in{(sockaddr_in*)&clientAddrMock};
    sa_in->sin_family = AF_INET;
    sa_in->sin_port = htons(50000u);
    inet_pton(AF_INET, "192.168.1.2", &sa_in->sin_addr);
    socklen_t socklen = sizeof(sockaddr_storage);

    // Instantiate mocked sys_socket object
    MockSysSocket mock_sys_socket;
    // Inject mocked sys_socket object
    SysSocket sys_socket(&mock_sys_socket);

    int listen_sock = 3;
    int accept_sock = 4;

    EXPECT_CALL(mock_sys_socket, accept(listen_sock, _, Pointee(socklen)))
        .WillOnce(DoAll(SetArgPointee<1>(*sa), Return(accept_sock)));

    // Test Unit
    EXPECT_EQ(sys_socket.get_addr(listen_sock), "192.168.1.2:50000");
}
//-----------------------------------------------------------------------------

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

With executing the test I get:

[==========] Running 2 tests from 1 test suite.
[----------] Global test environment set-up.
[----------] 2 tests from MockedSysSocketTest
[ RUN      ] MockedSysSocketTest.call_real_sys_socket_accept
[       OK ] MockedSysSocketTest.call_real_sys_socket_accept (0 ms)
[ RUN      ] MockedSysSocketTest.mock_sys_socket_accept
[       OK ] MockedSysSocketTest.mock_sys_socket_accept (0 ms)
[----------] 2 tests from MockedSysSocketTest (0 ms total)

[----------] Global test environment tear-down
[==========] 2 tests from 1 test suite ran. (0 ms total)
[  PASSED  ] 2 tests.

Reference:
Practical example for Dependency Injection and mocking with Googlemock

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文