性能测试LoadRunner解决动态验证码问题

对于这个问题,通常我们可以采取以下三个途径来解决该问题: 

1、第一种方法,也是最容易想到的,在被测系统中暂时屏蔽验证功能,也就是说,临时修改应用,无论用户输入的是什么验证码,都认为是正确的。这种方法最容易实现,对测试结果也不会有太大的影响(当然,这种方式去掉了“验证验证码”这个环节,不过这个环节本来就很难成为系统性能瓶颈)。但这种方法有一个致命的问题:如果被测系统是一个实际已上线的系统,屏蔽验证功能会对已经在运行的业务造成非常大的安全性的风险,因此,对于已上线的系统来说,用这种方式就不合适了;     

2、第二种方法,在第一种方法的基础上稍微进行一些改进。第一种方法带来了很大的安全性问题,那么我们可以考虑,不取消验证,但在其中留一个后门,我们设定一个所谓的“万能验证码”,只要用户输入这个“万能验证码”,我们就验证通过,否则,还是按照原先的验证方式进行验证。这种方式仍然存在安全性的问题,但由于我们可以通过管理手段将“万能验证码”控制在一个小的范围内,而且只在性能测试期间保留这个小小的后门,相对第一种方法来说,在安全性方面已经有较大的改进了;

3、如果安全性对应用来说真的是至关重要的,不容许有一丝一毫的闪失,那我们还可以用更进一步的方法来处理这个问题。a)一般的性能测试工具(MI的LR、Seague的Silk performer等)都能够调用外部的DLL或是组件接口,因此,可以考虑获得“验证码验证”部分的实现,写一个验证码获取的DLL,在测试脚本中进行调用即可。  b)或者用一个请求去刷新认证码页面,然后通过关联将返回的图片保存为硬盘的一个文件,然后用ocr(光学字符识别)去识别这个文件内容,保存结果到txt,最后用LR读这个文本。

方法a)示例:

在脚本里添加函数解决验证码的问题,当然这种方法绕过服务器,但还是可行的

步骤一:编写一个GUID.h的头文件,里面包含一个由26个字母和9个数字随机产生的一串随机数的GUID方法,代码如下:

  1. //GUID.h

  2. char* lr_guid_gen(char* paramName){ //生成GUID方法

  3. typedef struct _GUID {

  4. unsigned long Data1;

  5. unsigned short Data2;

  6. unsigned short Data3;

  7. unsigned char Data4[8];

  8. } GUID;

  9. GUID m_guid;

  10. char buf[50];

  11. char pNameStr[50];

  12. CoCreateGuid(&m_guid);

  13. // 定义输出格式

  14. sprintf (buf, "{%08lX-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}", // 大写

  15. // sprintf (buf, "{%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}",// 小写

  16. //sprintf (buf, "%08lX%04X%04X%02X%02X%02X%02X%02X%02X%02X%02X",// 小写

  17. m_guid.Data1, m_guid.Data2, m_guid.Data3,

  18. m_guid.Data4[0], m_guid.Data4[1], m_guid.Data4[2], m_guid.Data4[3],

  19. m_guid.Data4[4], m_guid.Data4[5], m_guid.Data4[6], m_guid.Data4[7]);

  20. lr_save_string(buf, paramName);

  21. sprintf(pNameStr,"{%s}",paramName);

  22. return lr_eval_string(pNameStr);

  23. }

步骤二:然后再编写一个头文件verify.h,里面包含一个获取上面生成随机字符串的验证码,比如下面代码(获取上述字符串的第5位开始截取六个长度的验证码)

  1. //verify.h 验证码头文件

  2. #define VALIDATESTART5//default 5

  3. #define VALIDATENUM6//default 6

  4. //!!!!!warn: must free the return point in your own program, or it will leak memory

  5. char* GetValidate(char *str)

  6. {

  7. // init some var

  8. char *pSrc = str;

  9. char *pDst = NULL;

  10. char *pHeader = NULL;

  11. int cnt = 0; //the current num of character in the pHeader

  12. if (pSrc == NULL) //chech the string is validate or not

  13. {

  14. return NULL;

  15. }

  16. pDst = (char *)malloc(sizeof(char)*(VALIDATENUM + 1)); //malloc dynamic memory

  17. pHeader= pDst;//record the head addr

  18. pSrc = pSrc + (VALIDATESTART - 1);//find the start pos

  19. while (*pSrc != '\0' && cnt != VALIDATENUM)

  20. {

  21. if ( *pSrc != '-')

  22. {

  23. *pDst++ = *pSrc;

  24. cnt++;

  25. }

  26. pSrc++;

  27. }

  28. *pDst = '\0';//add the last end character '\0'

  29. return pHeader;

  30. }

步骤三:将两个头文件加入globals.h里,我们就可以调用这两个函数了,不如在action调用,可以再脚本前面加上如下代码:

  1. char *test;char *test1;

  2. lr_load_dll("ole32.dll"); //引用windows生成GUID的API

  3. test=lr_guid_gen("GUID"); //调用上面lr_guid_gen()方法

  4. lr_save_string(test,"GUID");

  5. lr_output_message(test);

  6. lr_output_message("xxxxxxxxxxxxx:%s",lr_eval_string("{GUID}")); //生成随机字符串

  7. test1=GetValidate(test); //获取验证码

  8. lr_save_string(test1,"ID");

  9. lr_output_message("%s",lr_eval_string("{ID}"));

这样就算完成了,记得加入一句获取验证码图片的脚本哦!

方法b)示例:

代码如下:

  1. Action()

  2. { int flen; //定义一个整型变量保存获得文件的大小

  3. long filedes; //保存文件句柄

  4. char file[256]="D:\\test1.png"; //保存文件路径及文件名

  5. char result[5]; //存放验证码的,必须大于验证码的位数

  6. web_set_max_html_param_len("20000"); //设置参数的最大长度,注意该值必须大于文件的大小

  7. web_url("login",

  8. "URL=http://X.X.X.X/Kindergarten/login/login",

  9. "Resource=0",

  10. "RecContentType=text/html",

  11. "Referer=",

  12. "Snapshot=t1.inf",

  13. "Mode=HTTP",

  14. LAST);

  15. //使用关联函数获取下载文件的内容,在这里不定义左右边界,获得服务器响应的所有内容

  16. web_reg_save_param("pic",

  17. "LB=",

  18. "RB=",

  19. "SEARCH=BODY",

  20. LAST);

  21. //发送下载验证码的请求

  22. web_url("voliCode",

  23. "URL=http://X.X.X.X/Kindergarten/login/voliCode?d=1446432884699",

  24. "Resource=0",

  25. "RecContentType=text/html",

  26. "Referer=",

  27. "Snapshot=t1.inf",

  28. "Mode=HTTP",

  29. LAST);

  30. flen = web_get_int_property(HTTP_INFO_DOWNLOAD_SIZE); //获取响应中的文件长度

  31. if(flen > 0)

  32. {

  33. //以写方式打开文件

  34. if((filedes = fopen(file, "wb")) == NULL)

  35. {

  36. lr_output_message("打开文件失败!");

  37. return -1;

  38. }

  39. fwrite(lr_eval_string("{pic}"), flen, 1, filedes); //写入文件内容

  40. fclose(filedes); //关闭文件

  41. }

  42. system("D:\\test.bat");

  43. if((filedes=fopen("D:\\test.txt","rt"))== NULL)

  44. {

  45. lr_output_message("打开test.txt文件失败!");

  46. return -1;

  47. }

  48. fread(result,4,1,filedes);

  49. fclose(filedes);

  50. lr_output_message("the velue3 is: %s",result);

  51. lr_save_string(result,"check");

  52. lr_output_message("the check is %s",lr_eval_string("{check}"));

  53. lr_start_transaction("登录");

  54. web_submit_data("userLogin",

  55. "Action=http://X.X.X.X/Kindergarten/login/userLogin",

  56. "Method=POST",

  57. "RecContentType=text/html",

  58. "Referer=http://X.X.X.X/Kindergarten/login/login",

  59. "Snapshot=t13.inf",

  60. "Mode=HTTP",

  61. ITEMDATA,

  62. "Name=username", "Value=17715290001", ENDITEM,

  63. "Name=password", "Value=123456", ENDITEM,

  64. "Name=code", "Value={check}", ENDITEM,

  65. LAST);

  66. lr_end_transaction("登录",LR_AUTO);

  67. //验证登录是否成功:登录进去后再提交一次数据交互的请求

  68. lr_start_transaction("修改密码");

  69. web_submit_data("changePwd",

  70. "Action=http://X.X.X.X/Kindergarten/sys/changePwd",

  71. "Method=POST",

  72. "RecContentType=application/json",

  73. "Referer=http://X.X.X.X/Kindergarten/sys/changePwdView",

  74. "Snapshot=t53.inf",

  75. "Mode=HTTP",

  76. ITEMDATA,

  77. "Name=oPwd", "Value=123456", ENDITEM,

  78. "Name=nPwd", "Value=qwaszx", ENDITEM,

  79. "Name=nPwd2", "Value=qwaszx", ENDITEM,

  80. LAST);

  81. lr_end_transaction("修改密码",LR_AUTO);

  82. return 0;

  83. }

备注:

1、char result[5];这个是定义存放验证码的,必须大于验证码的位数,否则最后文件读出来的验证码后面会自动加入几个乱码字符;

2、 system("D:\\test.bat");  执行test.bat,注意D盘和test.bat之间是\\,盘符要转义;  test.bat内容如下:

    D:\InstallSoftware\Tesseract-OCR\tesseract.exe d:\test1.png d:\test -1   (tesseract.exe必须安装目录也写进去)

3、我测试的系统登录的url是 http://X.X.X.X/Kindergarten/login/login, 如果直接获取该网址的文件来获取验证码,文件太大,会失败;可以用火狐浏览器打开该网址,然后选中验证码,右键直接查看获取验证码的url,即:http://X.X.X.X/Kindergarten/login/voliCode?d=1446432884699; 然后再使用关联函数 web_reg_save_param获取 该url的下载内容;

4、回放的时候可以展示场景操作的页面,在 General Options--Display 里面设置,但是因为可能有缓存情况,所以不能根据登录成功后的系统页面来判断是否登录成功,最好是再操作一个数据交互的请求来判断是否登录成功;我的例子是再提交一个修改密码的操作来操作是否登录成功;

 

总结:

感谢每一个认真阅读我文章的人!!!

作为一位过来人也是希望大家少走一些弯路,如果你不想再体验一次学习时找不到资料,没人解答问题,坚持几天便放弃的感受的话,在这里我给大家分享一些自动化测试的学习资源,希望能给你前进的路上带来帮助。

软件测试面试文档

我们学习必然是为了找到高薪的工作,下面这些面试题是来自阿里、腾讯、字节等一线互联网大厂最新的面试资料,并且有字节大佬给出了权威的解答,刷完这一套面试资料相信大家都能找到满意的工作。

 

          视频文档获取方式:
这份文档和视频资料,对于想从事【软件测试】的朋友来说应该是最全面最完整的备战仓库,这个仓库也陪伴我走过了最艰难的路程,希望也能帮助到你!以上均可以分享,点下方小卡片即可自行领取。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值