自動化測試程式之二模擬觸控式螢幕點選事件和滑動事件(C語言)
一、測試程式編寫說明
終端裝置上執行的是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");
}
}
}
四、參考原始碼程式