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
  • 注 : 后续对参数拿到后的使用略,此为简易方案,效果仅供参考
相关推荐
vip45122 分钟前
Linux 经典面试八股文
linux
大霞上仙24 分钟前
Ubuntu系统电脑没有WiFi适配器
linux·运维·电脑
~yY…s<#>1 小时前
【刷题17】最小栈、栈的压入弹出、逆波兰表达式
c语言·数据结构·c++·算法·leetcode
孤客网络科技工作室2 小时前
VMware 虚拟机使用教程及 Kali Linux 安装指南
linux·虚拟机·kali linux
颇有几分姿色2 小时前
深入理解 Linux 内存管理:free 命令详解
linux·运维·服务器
AndyFrank3 小时前
mac crontab 不能使用问题简记
linux·运维·macos
筱源源3 小时前
Kafka-linux环境部署
linux·kafka
EricWang13583 小时前
[OS] 项目三-2-proc.c: exit(int status)
服务器·c语言·前端
我是谁??3 小时前
C/C++使用AddressSanitizer检测内存错误
c语言·c++
算法与编程之美4 小时前
文件的写入与读取
linux·运维·服务器