Skip to content

用户实现模式

用户实现模式允许你提供完整的 Mock 函数体,完全控制函数行为。

基本语法

c
__attribute__((mock))
返回类型 函数名(参数列表) {
    // 用户提供的实现
    return 返回值;
}

简单示例

c
#include <anvil/mock.h>

// Mock 传感器读取函数
__attribute__((mock))
int read_sensor(int sensor_id) {
    return 42;  // 始终返回 42
}

使用静态变量控制返回值

c
#include <anvil/mock.h>

static int mock_temperature = 25;

__attribute__((mock))
int read_sensor(int sensor_id) {
    return mock_temperature;
}

/*
 * 设计说明:测试正常温度
 * 预期结果:25度正常
 */
__attribute__((test_method))
int test_normal_temp(void) {
    mock_temperature = 25;
    return check_temp(0) == TEMP_NORMAL;
}

/*
 * 设计说明:测试高温告警
 * 预期结果:90度触发告警
 */
__attribute__((test_method))
int test_high_temp(void) {
    mock_temperature = 90;
    return check_temp(0) == TEMP_HIGH;
}

模拟错误条件

c
#include <anvil/mock.h>

static int mock_return_error = 0;

__attribute__((mock))
int read_file(const char *path, char *buf, int size) {
    if (mock_return_error) {
        return -1;  // 模拟读取错误
    }
    strcpy(buf, "mock data");
    return 9;
}

/*
 * 设计说明:测试文件读取错误处理
 * 预期结果:读取失败时返回错误码
 */
__attribute__((test_method))
int test_file_read_error(void) {
    mock_return_error = 1;
    int result = process_file("test.txt");
    mock_return_error = 0;
    return result == ERROR_READ_FAILED;
}

调用原始实现

使用 mock(func).call_real(...) 调用原始函数:

c
#include <anvil/mock.h>

static int call_count = 0;

__attribute__((mock))
int expensive_calculation(int x) {
    call_count++;
    // 前两次使用缓存值
    if (call_count <= 2) {
        return 100;
    }
    // 之后调用真实实现
    return mock(expensive_calculation).call_real(x);
}

验证调用参数

结合 Mock API 验证参数:

c
#include <anvil/mock.h>

__attribute__((mock))
int send_data(const char *host, int port, const char *data) {
    return 0;  // 成功
}

/*
 * 设计说明:验证发送参数正确
 * 预期结果:应使用正确的主机和端口
 */
__attribute__((test_method))
int test_send_params(void) {
    mock(send_data).reset();

    do_send("example.com", 8080, "hello");

    // 验证参数
    const char *host = *(const char **)mock(send_data).arg(0);
    int port = mock(send_data).arg1_val;

    return strcmp(host, "example.com") == 0 && port == 8080;
}

带状态的 Mock

c
#include <anvil/mock.h>

static int sensor_values[] = {20, 25, 30, 35, 40};
static int read_index = 0;

__attribute__((mock))
int read_sensor(int id) {
    if (read_index >= 5) {
        return -1;  // 没有更多数据
    }
    return sensor_values[read_index++];
}

__attribute__((test_initialize))
int setup(void) {
    read_index = 0;  // 重置索引
    return 0;
}

/*
 * 设计说明:测试连续读取
 * 预期结果:应依次返回预设值
 */
__attribute__((test_method))
int test_sequential_read(void) {
    return read_sensor(0) == 20 &&
           read_sensor(0) == 25 &&
           read_sensor(0) == 30;
}

完整示例

c
#include "network.h"
#include <anvil/mock.h>
#include <string.h>

// Mock 状态
static int mock_connect_result = 0;
static int mock_send_result = 0;
static char mock_recv_data[256] = "";

// Mock 网络连接
__attribute__((mock))
int net_connect(const char *host, int port) {
    return mock_connect_result;
}

// Mock 发送数据
__attribute__((mock))
int net_send(int fd, const char *data, int len) {
    if (mock_send_result < 0) {
        return mock_send_result;
    }
    return len;  // 返回发送的字节数
}

// Mock 接收数据
__attribute__((mock))
int net_recv(int fd, char *buf, int len) {
    int data_len = strlen(mock_recv_data);
    if (data_len == 0) {
        return 0;
    }
    strncpy(buf, mock_recv_data, len);
    return data_len < len ? data_len : len;
}

__attribute__((test_initialize))
int setup(void) {
    mock_connect_result = 0;
    mock_send_result = 0;
    mock_recv_data[0] = '\0';
    mock(net_connect).reset();
    mock(net_send).reset();
    mock(net_recv).reset();
    return 0;
}

/*
 * 设计说明:测试正常通信流程
 * 预期结果:发送请求后收到响应
 */
__attribute__((test_method))
int test_normal_communication(void) {
    strcpy(mock_recv_data, "HTTP/1.1 200 OK");

    char response[256];
    int result = http_get("example.com", 80, "/", response, 256);

    return result == 0 && strstr(response, "200 OK") != NULL;
}

/*
 * 设计说明:测试连接失败处理
 * 预期结果:连接失败时返回错误码
 */
__attribute__((test_method))
int test_connect_failure(void) {
    mock_connect_result = -1;

    char response[256];
    int result = http_get("example.com", 80, "/", response, 256);

    return result == ERROR_CONNECT_FAILED;
}

// includes: -I../include

本页面内容遵循 Luna 软件源代码授权条款 (LSLA) 发布