书接上文,本篇以C语言为例,介绍一下自动化脚本的编程框架(篇末有整体代码)。
框架的中心思想:
以函数指针形式,从脚本数组中按顺序依次执行脚本函数并判断执行结果。
若判断结果执行正确则指针向后偏移到下一个脚本函数。
若判断结果执行无效则指针不变重复此回合。
若判断结果执行出现问题需返回之前步骤,便将函数指针向前偏移到指定位置,继续执行接下来的脚本流程。
最终当所有脚本函数执行完毕后,自动化脚本运行完成。
由上一篇的自动化流程可知,每次脚本的执行会有三个事件,正常执行步骤、执行结果判断、错误后的环境处理。
于是我们定义一个脚本结构体,里面放这三个函数指针。
//执行函数定义
typedef int(*STEP)(int*, int**);
typedef struct
{
STEP step_go; //执行步骤函数
STEP step_judge; //执行结果判断
STEP step_error_deal; //错误后环境初始化
}s_script;
接着我们定义一个总体的脚本流程结构体,里面包含所有需执行的脚本步骤和当前正在执行的脚本步骤指针。
//本脚本的执行步数上限
#define STEP_NUM 20
typedef struct
{
int argc; //参数个数
int *argv; //参数数组
int script_all; //总共程序需要的步骤数量
s_script script[STEP_NUM]; //所有执行步骤
s_script *script_go; //当前正在执行的步骤
}s_robot;
这样我们两个关键的结构体已经定义好了,接下来随便写三个事件例程,并初始化一个测试脚本。
int test_go(int *argc, int **argv) //执行步骤函数测试用例
{
int *arg[ARG_NUM];
if (*argc > 0)
{
memcpy(*arg, *argv, *argc * sizeof(*argv));
*arg[0]++;
}
return 0;
}
int test_judge(int *argc, int **argv) //执行结果判断测试用例
{
return *argv[0];
}
int test_error_deal(int *argc, int **argv) //错误后环境初始化测试用例
{
*argv[0] = 0;
return 0;
}
s_script all_script[2] = {
{ test_go ,test_judge ,test_error_deal },
{ test_go ,test_judge ,test_error_deal }
};//测试脚本总步骤初始化,总步数只有2步
PS:别研究上述函数内部的指针运算,那些东西指来指去的,连我自己都指晕了,我这么说吧,它肯定不对,结果肯定不是我想要的,但本篇仅仅是框架,无需讨论运行结果。
然后我们对脚本流程结构体初始化。
//参数个数上限
#define ARG_NUM 20
int argv[ARG_NUM] = { 0 }; //参数数组初始化
s_robot test; //声明执行脚本测试用例
//脚本流程结构体初始化
test.argc = 1;
test.argv = argv;
test.script_all = sizeof(all_script) / sizeof(s_script);
for (int i = 0; i < test.script_all; i++)
{
test.script[i] = all_script[i];
}
test.script_go = &test.script[0];
//脚本流程结构体初始化
整体初始化流程:
先将参数数组指针指向参数。
设置脚本总共执行步数。
设置所有脚本的执行内容。
将当前正在执行的脚本步骤指针指向第一个脚本test.script[0]。
初始化完毕后,便可以开始执行了。
//开始执行
//循环终止条件为当前步骤执行函数为空 或 最后一步已正确执行完毕
while (
((*test.script_go).step_go != NULL) &&
(test.script_go < &test.script[test.script_all])
)
{
//执行当前步骤
(*test.script_go).step_go(&test.argc, &test.argv);
//判断执行后的结果
int judge = (*test.script_go).step_judge(&test.argc, &test.argv);
if (judge == 0) //执行正确
{
test.script_go++; //执行下一步
}
else
{
if (judge == -1) //执行失效
{
continue; //重复执行
}
else //执行错误
{
//错误后环境初始化
(*test.script_go).step_error_deal(&test.argc, &test.argv);
//跳转到指定执行步骤
test.script_go += (judge - 1);
}
}
}
此部分代码是例程代码,没有实际意义,也没有固定模式。
judge在此的实际作用是(偏移步数+1)。
执行正确时返回0,指针偏移步数应该是1。
执行失效时返回-1,指针偏移步数应该是0。
执行错误时判断需返回到的步骤,然后将步数返回,此返回数值可以根据自己喜好设置为当前步骤偏移值或需跳转的步骤序号(一个是相对路径,一个是绝对路径)。
传入的参数在每个函数中都可做修改,为下一个函数做参数初始化。当然也可以直接把参数做成全局变量,函数就无需再做参数传入。更甚至可以做个参数多维数组,为每个函数都设置好对应的参数。
至此,整体的自动化脚本编程框架已经全部成型,剩下的工作就是为每个脚本步骤设置实际的脚本函数。
整体代码如下:
#include <stdio.h>
#include <string.h>
//执行步数上限
#define STEP_NUM 20
//参数个数上限
#define ARG_NUM 20
//执行函数定义
typedef int(*STEP)(int*, int**);
typedef struct
{
STEP step_go; //执行步骤函数
STEP step_judge; //执行结果判断
STEP step_error_deal; //错误后环境初始化
}s_script;
typedef struct
{
int argc; //参数个数
int *argv; //参数数组
int script_all; //总共程序需要的步骤数量
s_script script[STEP_NUM]; //所有执行步骤
s_script *script_go; //当前正在执行的步骤
}s_robot;
int test_go(int *argc, int **argv) //执行步骤函数测试用例
{
int *arg[ARG_NUM];
if (*argc > 0)
{
memcpy(*arg, *argv, *argc * sizeof(*argv));
*arg[0]++;
}
return 0;
}
int test_judge(int *argc, int **argv) //执行结果判断测试用例
{
return *argv[0];
}
int test_error_deal(int *argc, int **argv) //错误后环境初始化测试用例
{
*argv[0] = 0;
return 0;
}
int main()
{
int argv[ARG_NUM] = { 0 }; //参数数组初始化
s_robot test; //声明执行脚本测试用例
s_script all_script[2] = { { test_go ,test_judge ,test_error_deal },
{ test_go ,test_judge ,test_error_deal } };//测试脚本总步骤初始化,只有2步
//脚本流程结构体初始化
test.argc = 1;
test.argv = argv;
test.script_all = sizeof(all_script) / sizeof(s_script);
test.script_go = &test.script[0];
for (int i = 0; i < test.script_all; i++)
{
test.script[i] = all_script[i];
}
//脚本流程结构体初始化
//开始执行
while (((*test.script_go).step_go != NULL) && (test.script_go < &test.script[test.script_all]))
{
(*test.script_go).step_go(&test.argc, &test.argv); //执行当前步骤
int judge = (*test.script_go).step_judge(&test.argc, &test.argv); //判断执行后的结果
if (judge == 0) //执行正确
{
test.script_go++; //执行下一步
}
else
{
if (judge == -1) //执行失效
{
continue; //重复执行
}
else //执行错误
{
(*test.script_go).step_error_deal(&test.argc, &test.argv); //错误后环境初始化
test.script_go += (judge - 1); //跳转到指定执行步骤
}
}
}
return 0;
}
目前本篇内容仅为理论,并未进行实战测试,所以仍会存在很多细节上的不足,需要进一步完善。
后续等本人实战结束后,会再发布一篇实战篇,将完善后的框架和测试心得分享给大家。
写在文末:
本人非科班出身,纯自学编程,所以很多理论框架全凭自己构想,也经常会有一些框架构想完毕并运用熟练后,结果又在后续的学习工作中发现这些框架早就已经被前人总结出来了。
所以各位读者大佬们如果发现这篇《自动化脚本编程框架》在别的书籍中有人总结或提出过类似的东西,请务必在评论区留言告知,我也免得自己再钻这些理论东西。