<!--[if !vml]--><!--[endif]-->驗證碼給自動測試帶來了很大的問題,但也并不是完全不能解決。結合我們在上文討論的驗證碼實現的方法,圖4給出了驗證碼實現的大致原理圖。
從圖4中可以看到,從技術的角度來看,至少設計兩種不同的方法來實現自動測試工具對驗證碼的處理:
<!--[if !supportLists]-->1、 <!--[endif]-->完全從客戶端角度考慮,靠模式識別的方法識別出驗證碼圖片對應的字符串;
<!--[if !supportLists]-->2、 <!--[endif]-->從服務端角度考慮,如果自動測試工具可以獲取Session中存儲的隨機數,也就能正確處理驗證碼了。
這兩種方法是解決自動化測試中驗證碼問題的主要方法,我們分別稱其為識別法和服務端插入法。這兩種方法在實現方法上側重點不同,適用的場合也不同。
識別法完全不用考慮服務端應用的實現,通過各種技術方法對顯示的驗證碼圖片進行“破譯”,這樣,即使完全不能接觸到服務端代碼,也能讓自動化測試在有驗證碼的情況下進行下去;但這種方法當然也有其致命的缺點:只能對簡單的驗證碼進行識別,對復雜的驗證碼,根本就無法識別。
而服務端插入法則從服務端入手,通過提供一個額外的客戶端接口,向客戶端只需要知道該接口的調用方法,就能通過該接口來獲取該頁面的驗證碼圖片對應的實際數據,并使用該數據繼續測試。
另一方面,除了技術角度解決問題的方法以外,還可以通過一些非技術的方法來解決驗證碼問題。
<!--[if !supportLists]-->4.1 <!--[endif]-->識別法的實現
識別法適用于不能獲得和改變服務器端代碼的情況下,在這種情況下,由于服務端代碼本身不可獲得,或是不能對其進行修改,測試者只能完全從客戶端的角度想辦法解決驗證碼的問題。
識別法的核心是對驗證碼圖片的模式識別算法,該算法的可實現性基本取決于圖片本身的復雜程度。以本文前面列舉的驗證碼示例來說,類似Gmail和Hotmail的驗證碼基本上是無法通過程序來識別的。而最簡單的驗證碼實現,例如ASP下用xbm技術生成的圖片,就可以很容易地通過算法來識別;在PHP、dotNET等平臺上完全使用圖形庫函數生成的圖片,同樣可以通過對某個區域內的圖片分析,識別出圖片對應的實際數字或是字母。
下面以處理xbm格式的驗證碼為例,介紹對其進行識別的算法。
本文的2.1節對xbm文件格式進行了深入的探討,用xbm實現驗證碼的方法在ASP和dotNET平臺上非常常見,由于xbm文件格式的規則性,因此很容易通過程序對其進行識別。一般的識別過程如下:
<!--[if !supportLists]-->多次訪問帶有驗證碼的頁面,分析每次獲得的xbm文件和顯示的圖片之間的對應關系,獲得驗證碼中所有符號對應的十六進制串;
<!--[if !supportLists]-->編寫識別驗證碼的代碼,識別代碼根據獲得的xbm文件,將其按照編碼方式分組,然后與上一步驟中獲得的對應的十六進制串進行比較,這樣就可以識別出該xbm文件對應的驗證碼的實際數據。
下面這段代碼是用于將xbm圖片文件識別為相應的驗證碼內容的C語言代碼:
int getDigital(char dig[10])
{
const char orgdig[10][10] = {
{0x3c,0x66,0xc3,0xc3,0xc3,0xc3,0xc3,0xc3,0x66,0x7e}, //0
{0x18,0x1c,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x00}, //1
{0x3c,0x66,0x60,0x60,0x30,0x18,0x0c,0x06,0x06,0x7e}, //2
{0x3c,0x66,0xc0,0x60,0x1c,0x60,0xc0,0xc0,0x66,0x38}, //3
{0x38,0x3c,0x36,0x33,0x33,0x33,0xff,0x30,0x30,0xfe}, //4
{0xfe,0xfe,0x06,0x06,0x3e,0x60,0xc0,0xc3,0x66,0x3c}, //5
{0x60,0x30,0x18,0x0c,0x3e,0x63,0xc3,0xc3,0x66,0x3c}, //6
{0xff,0xc0,0x60,0x30,0x18,0x18,0x18,0x18,0x18,0x18}, //7
{0x3c,0x66,0xc3,0x66,0x3c,0x66,0xc3,0xc3,0x66,0x3c}, //8
{0x3c,0x66,0xc3,0xc3,0x66,0x3c,0x18,0x0c,0x06,0x03} //9
};
int i=0, j=0;
int ret = 1;
for(i=0; i<10; i++)
{
ret = 1;
for(j=0; j<10; j++)
{
if(orgdig[i][j]!= dig[j])
{
ret = 0;
break;
}
}
if(ret)
return i;
}
return -1;
}
主函數:
char picc[500], t[40], od[10];
char separators[] = ",";
char *token, *endstr;
int i=0, j=0;
//獲取需要識別的圖片中的數據描述部分,內容為
//0x3c, 0x3c, 0x18, 0x3c, 0x66 …
//將其存放在字符串picc中
…………
//分解獲得的串
token = (char *)strtok(picc, separators); /* Get the first token */
if(!token)
{
return( -1 );
}
while( token != NULL )
{
if(!strcmp(token , "")) //處理為“空”的內容,將其替換成0x00
t[i] = 0x00;
else
t[i] = strtol(token, &endstr, 16);
i++;
token = (char *)strtok(NULL, separators);
}
for(i=0; i<4; i++) //一共4個數字,分別調用getDigital函數進行處理
{
for(j=0; j<10; j++)
原文轉自:http://www.anti-gravitydesign.com