一、测试程序编写说明
终端设备上运行的是LINUX+QT应用程序,使用触摸屏进行人机交互。经过测试人员长时间的人机交互测试,来确认系统的功能是否满足需求后。现在需要编写一个自动化的测试程序模拟触摸屏点击事件和滑动,并能够按照测试人员预设的脚本执行,比如在屏幕的某个位置需要点击某个按钮,或是屏幕或是列表需要滑动,并且这一个或几个动作需要连续执行10000次或更多。通过这样的自动测试,可以减轻测试人员的负担,还可以查看画面按钮触发N次后,画面执行N次后的系统的稳定性,如内存使用率(内存是否泄漏),cup使用率(负载是否很高)等等。
二、测试程序的结构分析
根据上述的简单要求,先分析测试程序的基本逻辑结构是程序通过读脚本中动作以及坐标来执行。
脚本文件以TXT文本形式记录,
P表示点击操作,P x y 3000:点击(x,y)点后等待3000毫秒做下一个动作
S表示滑动操作,S x1 y1 x2 y2 2000:从(x1,y1)点滑动到(x2,y2)点,等待2000毫秒做下一个动作
当前只支持垂直或是水平匀速滑动。(屏幕任意两点的滑动暂时不支持)
R表示重复,R Rounds Ln:表示以下Ln行重复Rounds次,该指令是可选的,如果不写顺序执行脚本。
脚本文本文件示例如下:
——–Sample1.txt————–
R 15000 2
P 973 545 1000 goButton
P 630 750 1000 BackButton
表示点击两个按钮,这两个点击按钮动作循环执行15000次,每次点击指定的坐标后,等待1000毫秒。
——–Sample2.txt————–
R 10000 2
S 200 300 801 300 5000 SlidingLeftToRight
S 800 100 202 100 5000 SlidingRightToLeft
表示在当前页面左右滑动,先由点(200,300)水平向右滑动到点(801,300),sleep 5秒,再由点(800,100)水平向左滑动懂点(202,100),sleep 5秒。
三、测试程序实现主要逻辑
1、定义链表结构
typedef struct List
{
int operIndex;
char operation;
int microseconds; //微秒数
int i_StartX; //点击的X坐标,或是滑动的开始点X坐标
int i_StartY; //点击的Y坐标,或是滑动的开始点Y坐标
int i_EndX; //滑动的结束点X坐标
int i_EndY; //滑动的结束点Y坐标
int i_repeatCnt;//重复的次数
int i_repeatLine;//以下动作重复的行数
FLAG c_flag;// HEADER or Member
char str_note[200]; //动作说明
struct List *nextGp; //指针域
struct List *repeatStart;//设定重复的头的位置
}List;
List *oprtData_Set;
2、上报输入事件(input_event)
int reportkey(int fd, uint16_t type, uint16_t code, int32_t value)
{
struct input_event event;
event.type = type;
event.code = code;
event.value = value;
gettimeofday(&event.time, 0);
if (write(fd, &event, sizeof(struct input_event)) < 0) {
printf("report key error!\n");
return -1;
}
return 0;
}
3、尾插法构造动作序列的链表
void TailCreatList(List *L,char * fname) //尾插法建立链表
{
List *tmpData;
List *tail ;
List *pRepeatHeader;
int i_repeatCnt = 0;
int i_repeatLines = 0;
char c_repeatID;
REPEAT flag = NoRepeatPos; //
char buffer[512];
char c_Oper_temp;
FILE *infile;
infile=fopen(fname,"r");
int index=0;
tail=L; //NULL
pRepeatHeader=tail->nextGp;//NULL
if(infile==NULL)
{
printf("\nFailed to open the file : %s \n",fname);
exit(0);
}
else
{
printf("open success! \n");
}
memset(buffer,0,sizeof(buffer));
while ( fgets(buffer, sizeof(buffer), infile))
{
tmpData=(struct List*)malloc(sizeof(struct List));
if(!tmpData)
{
printf("malloc() error@TailCreatList \n");
exit(0);
}
memset(tmpData,0,sizeof(struct List));
tmpData->nextGp=NULL;
tmpData->repeatStart=NULL;
sscanf(buffer,"%c",&c_Oper_temp);
if(c_Oper_temp == 'p' || c_Oper_temp == 'P' ) // 点击事件
{
index++;
sscanf( buffer,"%c %d %d %d %s",&(tmpData->operation),&(tmpData->i_StartX),&(tmpData->i_StartY),&(tmpData->microseconds),&(tmpData->str_note));
tmpData->operIndex=index;
tmpData->nextGp=NULL;
tmpData->repeatStart=NULL; //初始化结构体
if(flag == RepeatPos ) //设定头指针
{
tmpData->i_repeatCnt=i_repeatCnt;
tmpData->i_repeatLine=i_repeatLines; //处于循环位置的第一个节点,设置循环次数和循环的行数
pRepeatHeader = tmpData;
tmpData->repeatStart = pRepeatHeader;
flag = NoRepeatPos;
i_repeatLines--;
//行数减一
tail->nextGp=tmpData; //移动指针 未插入链表
tail=tmpData;
memset(buffer,0,sizeof(buffer));
continue; //继续循环
}
if(pRepeatHeader!=NULL && i_repeatLines>0) //未循环完了,并且存在头直指
{
i_repeatLines--;
tmpData->repeatStart = pRepeatHeader;
tail->repeatStart = NULL;
tail->nextGp=tmpData; //移动指针 尾部插入链表
tail=tmpData;
memset(buffer,0,sizeof(buffer));
continue; //继续循环
}
if(i_repeatLines = 0) //循环完了 (循环完了 或是根本没有循环)
{
pRepeatHeader =NULL; //复位循环头的指针,使之为空。
flag = NoRepeatPos;//标志位复位
}
tail->nextGp=tmpData; //移动指针 尾部插入链表
tail=tmpData;
}
else if (c_Oper_temp == 's' || c_Oper_temp == 'S' ) //滑动事件
{
index++;
//构造滑动动作
sscanf( buffer,"%c %d %d %d %d %d %s",&(tmpData->operation),
&(tmpData->i_StartX),&(tmpData->i_StartY),
&(tmpData->i_EndX),&(tmpData->i_EndY),
&(tmpData->microseconds),
&(tmpData->str_note));
tmpData->operIndex=index;
tmpData->nextGp=NULL;
tmpData->repeatStart=NULL; //初始化结构体
if(flag == RepeatPos ) //设定头指针
{
tmpData->i_repeatCnt=i_repeatCnt;
tmpData->i_repeatLine=i_repeatLines; //处于循环位置的第一个节点,设置循环次数和循环的行数
pRepeatHeader = tmpData;
tmpData->repeatStart = pRepeatHeader;
flag = NoRepeatPos;
i_repeatLines--;
//行数减一
tail->nextGp=tmpData; //移动指针 未插入链表
tail=tmpData;
memset(buffer,0,sizeof(buffer));
continue; //继续循环
}
if(pRepeatHeader!=NULL && i_repeatLines>0) //未循环完了,并且存在头直指
{
i_repeatLines--;
tmpData->repeatStart = pRepeatHeader;
tail->repeatStart = NULL;
tail->nextGp=tmpData; //移动指针 尾部插入链表
tail=tmpData;
memset(buffer,0,sizeof(buffer));
continue; //继续循环
}
if(i_repeatLines = 0) //循环完了 (循环完了 或是根本没有循环)
{
pRepeatHeader =NULL; //复位循环头的指针,使之为空。
flag = NoRepeatPos;//标志位复位
}
tail->nextGp=tmpData; //移动指针 尾部插入链表
tail=tmpData;
}
else if (c_Oper_temp == 'R' || c_Oper_temp == 'r' ) //滑动事件
{
sscanf( buffer,"%c %d %d",&c_repeatID,&i_repeatCnt,&i_repeatLines );
printf( "Repeat = %c , i_repeatCnt = %d,RepeatLines = %d \n",c_repeatID,i_repeatCnt,i_repeatLines );
memset(buffer,0,sizeof(buffer));
flag = RepeatPos;
}
memset(buffer,0,sizeof(buffer));
}
tail->nextGp=NULL;
fclose(infile);
return ;
}
4、构造点击事件
注意 上报的顺序不要写错,一个事件的结束标志是上报一个EV_SYN事件
void LCD_Touch_Pressed(int posx,int posy,int sec)
{
printf("emit Point:(%d,%d),sleep %.2f secs\n",posx,posy,(float)sec/1000.0);
reportkey(TOUCH_FD,EV_ABS,ABS_X,posx);
reportkey(TOUCH_FD,EV_ABS,ABS_Y,posy); //report position x,y
reportkey(TOUCH_FD,EV_ABS,ABS_PRESSURE,200); //report preeusre 200
reportkey(TOUCH_FD,EV_KEY,BTN_TOUCH,1); //report touch preesed event
reportkey(TOUCH_FD,EV_SYN,EV_SYN,EV_SYN); //report syn signal , finish the curent event!
reportkey(TOUCH_FD,EV_ABS,ABS_PRESSURE,0); //report preeusre 0
reportkey(TOUCH_FD,EV_KEY,BTN_TOUCH,0); //report touch release event
reportkey(TOUCH_FD,EV_SYN,EV_SYN,EV_SYN); //report syn signal , finish the curent event!
}
5、构造滑动事件
void LCD_Press_Silding(int sx,int sy,int ex,int ey ,int sec)
{
int nextPosX,nextPosY;
printf("Siding from Point(%d,%d) to Point(%d,%d),sleep %.2f secs\n",sx,sy, ex, ey , (float)sec/1000.0);
if(ex == sx && ey==sy) // the same two points
{
LCD_Touch_Pressed(sx,sy,sec);
return ;
}
//*report First point */
// printf("(%d,%d) ",sx,sy);
/**Report pressed-down event START----*/
reportkey(TOUCH_FD,EV_ABS,ABS_X,sx);
reportkey(TOUCH_FD,EV_ABS,ABS_Y,sy); //report position x,y
reportkey(TOUCH_FD,EV_ABS,ABS_PRESSURE,200); //report preeusre 200
reportkey(TOUCH_FD,EV_KEY,BTN_TOUCH,1); //report touch preesed event
reportkey(TOUCH_FD,EV_SYN,EV_SYN,EV_SYN); //report syn signal , finish the curent event!
usleep(SILDING_DELAY);
/**Report pressed-down event END----*/
nextPosX = sx;
nextPosY = sy;
if(ex == sx) // vertical Line
{
nextPosY = ey > sy ? (nextPosY + SILDING_STEP) : (nextPosY - SILDING_STEP);
while (abs(nextPosY-sy)< abs(ey-sy))
{
// printf("(%d,%d), ",ex,nextPosY);
reportkey(TOUCH_FD,EV_ABS,ABS_X,ex);
reportkey(TOUCH_FD,EV_ABS,ABS_Y,nextPosY); //report position x,y
reportkey(TOUCH_FD,EV_SYN,EV_SYN,EV_SYN); //report syn signal , finish the curent event!
usleep(SILDING_DELAY);
nextPosY = ey > sy ? (nextPosY + SILDING_STEP) : (nextPosY - SILDING_STEP);
}
// printf("(%d,%d) \n",ex,ey); //report this last Point
reportkey(TOUCH_FD,EV_ABS,ABS_X,ex);
reportkey(TOUCH_FD,EV_ABS,ABS_Y,ey); //report position x,y
reportkey(TOUCH_FD,EV_SYN,EV_SYN,EV_SYN); //report syn signal , finish the curent event!
reportkey(TOUCH_FD,EV_ABS,ABS_PRESSURE,0); //report preeusre 0
reportkey(TOUCH_FD,EV_KEY,BTN_TOUCH,0); //report touch release event
reportkey(TOUCH_FD,EV_SYN,EV_SYN,EV_SYN); //report syn signal , finish the curent event!
return;
}
if(ey == sy) // horizontal Line
{
nextPosX = ex > sx ? (nextPosX + SILDING_STEP) : (nextPosX - SILDING_STEP);
while (abs(nextPosX-sx)< abs(ex-sx))
{
// printf("(%d,%d), ",nextPosX,ey);
reportkey(TOUCH_FD,EV_ABS,ABS_X,nextPosX);
reportkey(TOUCH_FD,EV_ABS,ABS_Y,ey); //report position x,y
reportkey(TOUCH_FD,EV_SYN,EV_SYN,EV_SYN); //report syn signal , finish the curent event!
usleep(SILDING_DELAY);
nextPosX = ex > sx ? (nextPosX + SILDING_STEP) : (nextPosX - SILDING_STEP);
}
// printf("(%d,%d) \n",ex,ey); //report this last Point
reportkey(TOUCH_FD,EV_ABS,ABS_X,ex);
reportkey(TOUCH_FD,EV_ABS,ABS_Y,ey); //report position x,y
reportkey(TOUCH_FD,EV_SYN,EV_SYN,EV_SYN); //report syn signal , finish the curent event!
reportkey(TOUCH_FD,EV_ABS,ABS_PRESSURE,0); //report preeusre 0
reportkey(TOUCH_FD,EV_KEY,BTN_TOUCH,0); //report touch release event
reportkey(TOUCH_FD,EV_SYN,EV_SYN,EV_SYN); //report syn signal , finish the curent event!
return;
}
printf("Siding from Point(%d,%d) to Point(%d,%d),sleep %d secs, this is A Oblique Line.\n",sx,sy, ex, ey , sec);
/* 斜线的情况 //NOT TO Do */
}
6、按照链表中的数据逐条发送触摸事件
void Touch_Event_Test(List *L)
{
List *p=L->nextGp;
printf("-------Touch_Event_Test-------\n");
int loop=0;
CYCLE_MODE mode_flag = FirstCycle;
int step=0;
int round=0;
while(p!=NULL)
{
if(p->operation == 'p' || p->operation == 'P' ) // 点击事件
{
printf("[%d:%d]",round,p->operIndex);
// printf("[%c,%d,%d %d] \n", p->operation,p->i_StartX,p->i_StartY,p->microseconds);
LCD_Touch_Pressed(p->i_StartX,p->i_StartY,p->microseconds);
usleep(p->microseconds * MSECONDS);
}
else if (p->operation == 's' || p->operation == 'S' ) //滑动事件
{
printf("[%d:%d]",round,p->operIndex);
//printf("[%c,%d,%d ; %d,%d %d] \n", p->operation,p->i_StartX,p->i_StartY,p->i_EndX,p->i_EndY,p->microseconds);
LCD_Press_Silding(p->i_StartX,p->i_StartY,p->i_EndX,p->i_EndY,p->microseconds);
usleep(p->microseconds * MSECONDS);
}
if(!p->repeatStart) //当前没有前向循环节点,
{
p = p->nextGp;
if(loop==0) //没有循环
round = 0;
else
round=round;//存在循环,round不变
}
else
{
if(mode_flag == FirstCycle && p->repeatStart->i_repeatCnt >0)
{
loop = p->repeatStart->i_repeatCnt;
mode_flag = OtherCycle;
p = p->repeatStart;
loop--;
round ++;
continue;
}
if( loop > 0 && mode_flag == OtherCycle )//未重复完
{
p = p->repeatStart;
loop--;
round ++;
continue;
}
mode_flag = FirstCycle;//循环完了, 恢复默认值,
round = 0;
p = p->nextGp;
printf("\n\n");
}
}
}
四、参考源码程序
http://download.csdn.net/detail/flyeagle022/8800319