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
  • 注 : 后续对参数拿到后的使用略,此为简易方案,效果仅供参考
相关推荐
C++忠实粉丝26 分钟前
Linux环境基础开发工具使用(2)
linux·运维·服务器
康熙38bdc1 小时前
Linux 环境变量
linux·运维·服务器
凯子坚持 c1 小时前
C语言复习概要(三)
c语言·开发语言
无限大.1 小时前
c语言200例 067
java·c语言·开发语言
无限大.1 小时前
c语言实例
c语言·数据结构·算法
Death2001 小时前
Qt 中的 QListWidget、QTreeWidget 和 QTableWidget:简化的数据展示控件
c语言·开发语言·c++·qt·c#
hakesashou2 小时前
python如何比较字符串
linux·开发语言·python
Ljubim.te2 小时前
Linux基于CentOS学习【进程状态】【进程优先级】【调度与切换】【进程挂起】【进程饥饿】
linux·学习·centos
Death2002 小时前
Qt 3D、QtQuick、QtQuick 3D 和 QML 的关系
c语言·c++·qt·3d·c#
洛临_2 小时前
【C语言】基础篇
c语言·算法