Linux C轻量级白盒测试方法 (shell + c + signal)

Linux C轻量级的白盒测试方法 (shell + c + signal)

简介

  • 目的:当我们写好一个程序,往往需要测试及调试以保证功能的正确性,有时借助gtest等单元测试工具进行测试,但也可以自己设计一种简单轻量化的白盒测试方法去做程序逻辑的测试或调试。
  • 分析:这其中的关键是将各个触发不同逻辑的参数传入逻辑代码,触发不同的业务执行,观测结果。
  • 设计:shell + c + signal, shell脚本将各个参数(参数列表)接收,由于linux下 pkill -USR1 process_name的信号发送命令不方便携带多参数场景,这里写入文件,并通过信号(用户信号USR1)通知c进程,C进程拿到信号后解析文件(文件内容为参数列表),解析出各个参数即可。之后便可根据各个参数做不同的逻辑测试执行逻辑。

源码

  • 信号发送脚本 send_signal.sh
bash 复制代码
#!/bin/bash

#if [ $# -lt 2 ]; then
if [ $# -lt 1 ]; then
#    echo "使用方法: $0 <id> <string1> [<string2> ...]"
    echo "使用方法: $0 <param1> <param2> [<param3> ...]"
    exit 1
fi

#ID=$1
#echo "ID: $ID"
#shift

# 创建一个文件,用于存储字符串参数
OUTPUT_FILE="./signal_params.txt"
echo -n "" > $OUTPUT_FILE

# 写入每个字符串参数
for param in "$@"
do
    echo "$param" >> $OUTPUT_FILE
done

# 获取目标 C 程序的进程 ID
TARGET_PID=$(pgrep -f signal_handler)

if [ -z "$TARGET_PID" ]; then
    echo "找不到目标程序的进程"
    exit 1
fi

echo "发送信号 SIGUSR1 到进程 ID: $TARGET_PID,参数值: $@"
sync
sleep 0.5

# 发送 SIGUSR1 信号到目标进程
kill -SIGUSR1 $TARGET_PID

echo "已发送信号 SIGUSR1 到进程 ID: $TARGET_PID,参数值: $@"
  • 信号接收c进程 signal_handler.c
c 复制代码
/* signal_handler.c */
#include <stdio.h>
#include <stdint.h>
#include <signal.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#define MAX_PARAMS 100
#define MAX_PARAM_LENGTH 256
#define SIGNAL_PARAMS_FILE_PATH "./signal_params.txt"

// 全局变量,用于存储字符串参数
static char *global_params[MAX_PARAMS];
static uint16_t global_params_count = 0;

void SignalHandler(int signal)
{
    FILE *file = fopen(SIGNAL_PARAMS_FILE_PATH, "r");
    if (file == NULL)
    {
        perror("无法打开参数文件");
        return;
    }

    // 清空之前的参数
    for (uint16_t i = 0; i < global_params_count; i++)
    {
        free(global_params[i]);
    }
    global_params_count = 0;

    // 读取每个字符串参数KF
    char buffer[MAX_PARAM_LENGTH];
    while (fgets(buffer, sizeof(buffer), file) != NULL)
    {
        buffer[strcspn(buffer, "\n")] = '\0'; // 移除换行符
        global_params[global_params_count] = strdup(buffer);
        global_params_count++;
        if (global_params_count >= MAX_PARAMS)
        {
            printf("signal count[%d] out of range[%d]\n", global_params_count, MAX_PARAMS);
            break;
        }
    }

    fclose(file);

    // 打印接收到的参数
    printf("信号[%d]处理程序被调用\n", signal);
    printf("接收到的参数个数: %u\n", global_params_count);
    for (uint16_t i = 0; i < global_params_count; i++)
    {
        printf("参数%u: %s\n", i + 1, global_params[i]);
    }
}

static void SignalRegister(void)
{
    // 绑定信号处理程序到 SIGUSR1 信号
    signal(SIGUSR1, SignalHandler);

    // 获取并打印当前进程 ID
    pid_t pid = getpid();
    printf("程序已启动,进程 ID: %d\n", pid);

    // 主循环,等待信号
    while (1)
    {
        pause(); // 等待信号
    }

    // 清理分配的内存
    for (uint16_t i = 0; i < global_params_count; i++)
    {
        free(global_params[i]);
    }

}

int main()
{
    SignalRegister();
    return 0;
}

用法

  • 编译并启动c进程等待信号(这里用用户信号)
bash 复制代码
gcc signal_handler.c -o signal_handler
./signal_handler &
[1] 3508
程序已启动,进程 ID: 3508
  • 脚本接收参数并发送信号和参数
bash 复制代码
chmod +x send_signal.sh
./send_signal.sh 
使用方法: ./send_signal.sh <param1> <param2> [<param3> ...]
  • 需要带参数,效果:
bash 复制代码
./send_signal.sh 1 2 3.14 key value 
发送信号 SIGUSR1 到进程 ID: 3508,参数值: 1 2 3.14 key value
已发送信号 SIGUSR1 到进程 ID: 3508,参数值: 1 2 3.14 key value
信号处理程序被调用: signal 10
接收到的参数个数: 5
参数1: 1
参数2: 2
参数3: 3.14
参数4: key
参数5: value
  • 文件内容 signal_params.txt
bash 复制代码
1
2
3.14
key
value
  • 注 : 后续对参数拿到后的使用略,此为简易方案,效果仅供参考
相关推荐
搬砖的小码农_Sky2 小时前
C语言:数组
c语言·数据结构
朝九晚五ฺ3 小时前
【Linux探索学习】第十四弹——进程优先级:深入理解操作系统中的进程优先级
linux·运维·学习
自由的dream3 小时前
Linux的桌面
linux
xiaozhiwise3 小时前
Makefile 之 自动化变量
linux
意疏5 小时前
【Linux 篇】Docker 的容器之海与镜像之岛:于 Linux 系统内探索容器化的奇妙航行
linux·docker
BLEACH-heiqiyihu6 小时前
RedHat7—Linux中kickstart自动安装脚本制作
linux·运维·服务器
一只爱撸猫的程序猿6 小时前
一个简单的Linux 服务器性能优化案例
linux·mysql·nginx
ahadee6 小时前
蓝桥杯每日真题 - 第19天
c语言·vscode·算法·蓝桥杯
Theliars6 小时前
C语言之字符串
c语言·开发语言