关于stub和mock

第一部分:C/C++中的Mock和Stub区别

基础概念

在C/C++单元测试中:

  • Stub(打桩):提供预设的返回值

  • Mock(模拟):验证函数调用行为

实际代码示例

假设我们有一个文件操作模块:

复制代码
// file_operations.h
#ifndef FILE_OPERATIONS_H
#define FILE_OPERATIONS_H

#include <stdbool.h>

typedef struct {
    bool (*file_exists)(const char* filename);
    int (*read_file)(const char* filename, char* buffer, int size);
} FileOperations;

bool process_config_file(const char* filename, FileOperations* ops);

#endif

// file_operations.c
#include "file_operations.h"
#include <stdio.h>
#include <string.h>

bool process_config_file(const char* filename, FileOperations* ops) {
    if (!ops->file_exists(filename)) {
        return false;
    }
    
    char buffer[256];
    int bytes_read = ops->read_file(filename, buffer, sizeof(buffer));
    return bytes_read > 0;
}

Stub(打桩)示例:

复制代码
// test_stub.c
#include "file_operations.h"
#include <assert.h>

// Stub 函数 - 只提供预设返回值,不关心调用细节
static bool stub_file_exists(const char* filename) {
    return true; // 总是返回文件存在
}

static int stub_read_file(const char* filename, char* buffer, int size) {
    const char* config_content = "timeout=30\nretries=3";
    strcpy(buffer, config_content);
    return strlen(config_content); // 返回预设内容
}

void test_with_stubs() {
    FileOperations stubs = {
        .file_exists = stub_file_exists,
        .read_file = stub_read_file
    };
    
    bool result = process_config_file("config.txt", &stubs);
    assert(result == true); // 只验证最终结果
}

Mock(模拟)示例:

复制代码
// test_mock.c
#include "file_operations.h"
#include <assert.h>
#include <string.h>

// Mock 结构体 - 记录调用信息
typedef struct {
    int file_exists_call_count;
    int read_file_call_count;
    char last_filename[256];
    bool file_exists_return;
    int read_file_return;
} FileOperationsMock;

static FileOperationsMock mock_data = {0};

// Mock 函数 - 记录调用行为
static bool mock_file_exists(const char* filename) {
    mock_data.file_exists_call_count++;
    strncpy(mock_data.last_filename, filename, sizeof(mock_data.last_filename)-1);
    return mock_data.file_exists_return;
}

static int mock_read_file(const char* filename, char* buffer, int size) {
    mock_data.read_file_call_count++;
    strncpy(mock_data.last_filename, filename, sizeof(mock_data.last_filename)-1);
    
    if (mock_data.read_file_return > 0) {
        const char* content = "timeout=30";
        strncpy(buffer, content, size-1);
        return strlen(content);
    }
    return mock_data.read_file_return;
}

void test_with_mocks() {
    // 重置 Mock 数据
    memset(&mock_data, 0, sizeof(mock_data));
    mock_data.file_exists_return = true;
    mock_data.read_file_return = 10;
    
    FileOperations mocks = {
        .file_exists = mock_file_exists,
        .read_file = mock_read_file
    };
    
    bool result = process_config_file("config.txt", &mocks);
    
    // Mock 验证:检查交互行为
    assert(mock_data.file_exists_call_count == 1);
    assert(mock_data.read_file_call_count == 1);
    assert(strcmp(mock_data.last_filename, "config.txt") == 0);
    assert(result == true);
}

使用Mock框架(如Google Mock)

对于C++,使用Google Mock框架更简单:

复制代码
// mock_example.cpp
#include <gmock/gmock.h>
#include <gtest/gtest.h>

class FileSystemInterface {
public:
    virtual ~FileSystemInterface() = default;
    virtual bool fileExists(const std::string& filename) = 0;
    virtual int readFile(const std::string& filename, char* buffer, int size) = 0;
};

class MockFileSystem : public FileSystemInterface {
public:
    MOCK_METHOD(bool, fileExists, (const std::string& filename), (override));
    MOCK_METHOD(int, readFile, (const std::string& filename, char* buffer, int size), (override));
};

TEST(FileProcessingTest, ProcessConfigFile) {
    MockFileSystem mock_fs;
    
    // Stubbing: 预设返回值
    EXPECT_CALL(mock_fs, fileExists("config.txt"))
        .WillOnce(testing::Return(true));
    
    EXPECT_CALL(mock_fs, readFile("config.txt", testing::_, testing::_))
        .WillOnce(testing::Return(10));
    
    // Mock验证: 自动验证调用次数和参数
    // Google Mock会验证上面的EXPECT_CALL是否满足
}
相关推荐
橘子真甜~7 小时前
C/C++ Linux网络编程15 - 网络层IP协议
linux·网络·c++·网络协议·tcp/ip·计算机网络·网络层
asiwxy8 小时前
OpenGL 材质
c++
阿华hhh9 小时前
Linux系统编程(标准io)
linux·开发语言·c++
程序喵大人9 小时前
推荐个 C++ 练习平台
开发语言·c++·工具推荐
fpcc10 小时前
跟我学C++中级篇——std::is_invocable的分析应
c++
Code Slacker12 小时前
LeetCode Hot100 —— 滑动窗口(面试纯背版)(四)
数据结构·c++·算法·leetcode
SHERlocked9313 小时前
摄像头 RTSP 流视频多路实时监控解决方案实践
c++·后端·音视频开发
tang&14 小时前
哈希碰撞攻防战:C++闭散列与开散列实现全解析
c++·哈希算法
眠りたいです14 小时前
现代C++:C++11并发支持库
开发语言·c++·多线程·c++11·c++并发支持库