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

news2025/2/23 7:32:03

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

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

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

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

方法a)示例:

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

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

//GUID.h
 
char* lr_guid_gen(char* paramName){                         //生成GUID方法
typedef struct _GUID    {
unsigned long Data1;
unsigned short Data2;
unsigned short Data3;
unsigned char Data4[8];
} GUID;
GUID m_guid;
char buf[50];
char pNameStr[50];
CoCreateGuid(&m_guid);
// 定义输出格式
sprintf (buf, "{%08lX-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}", // 大写
// sprintf (buf, "{%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}",// 小写
//sprintf (buf, "%08lX%04X%04X%02X%02X%02X%02X%02X%02X%02X%02X",// 小写
m_guid.Data1, m_guid.Data2, m_guid.Data3,
m_guid.Data4[0], m_guid.Data4[1], m_guid.Data4[2], m_guid.Data4[3],
m_guid.Data4[4], m_guid.Data4[5], m_guid.Data4[6], m_guid.Data4[7]);
lr_save_string(buf, paramName);
sprintf(pNameStr,"{%s}",paramName);
return lr_eval_string(pNameStr);
}

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

//verify.h  验证码头文件
 
#define VALIDATESTART5//default 5
#define VALIDATENUM6//default 6
 
 
//!!!!!warn: must free the return point in your own program, or it will leak memory
char* GetValidate(char *str)
{
// init some var
char *pSrc = str;  
char *pDst = NULL;
char *pHeader = NULL;
int cnt = 0; //the current num of character in the pHeader
 
 
if (pSrc == NULL) //chech the string is validate or not 
{
return NULL;
}
pDst = (char *)malloc(sizeof(char)*(VALIDATENUM + 1)); //malloc dynamic memory
pHeader= pDst;//record the head addr
pSrc = pSrc + (VALIDATESTART - 1);//find the start pos
while (*pSrc != '\0' && cnt != VALIDATENUM) 
{
if ( *pSrc != '-')
{
*pDst++ = *pSrc;
cnt++;
}
pSrc++;
}
*pDst = '\0';//add the last end character '\0'
return pHeader;
}

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

   char *test;char *test1;
    lr_load_dll("ole32.dll");      //引用windows生成GUID的API
   test=lr_guid_gen("GUID");      //调用上面lr_guid_gen()方法
    lr_save_string(test,"GUID");
    lr_output_message(test);
    lr_output_message("xxxxxxxxxxxxx:%s",lr_eval_string("{GUID}"));    //生成随机字符串
   test1=GetValidate(test);         //获取验证码
 
   lr_save_string(test1,"ID");
 
   lr_output_message("%s",lr_eval_string("{ID}"));

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

方法b)示例:

代码如下:

Action()
 
{  int flen;    //定义一个整型变量保存获得文件的大小
 
  long filedes;    //保存文件句柄
      char file[256]="D:\\test1.png";    //保存文件路径及文件名
      char result[5];   //存放验证码的,必须大于验证码的位数
     web_set_max_html_param_len("20000");     //设置参数的最大长度,注意该值必须大于文件的大小
   
web_url("login", 
"URL=http://X.X.X.X/Kindergarten/login/login", 
"Resource=0", 
"RecContentType=text/html", 
"Referer=", 
"Snapshot=t1.inf", 
"Mode=HTTP", 
LAST);  
 
//使用关联函数获取下载文件的内容,在这里不定义左右边界,获得服务器响应的所有内容
web_reg_save_param("pic",
    "LB=",
    "RB=",
     "SEARCH=BODY",
        LAST);
    //发送下载验证码的请求
web_url("voliCode", 
"URL=http://X.X.X.X/Kindergarten/login/voliCode?d=1446432884699", 
"Resource=0", 
"RecContentType=text/html", 
"Referer=", 
"Snapshot=t1.inf", 
"Mode=HTTP", 
LAST); 
 
 flen = web_get_int_property(HTTP_INFO_DOWNLOAD_SIZE);   //获取响应中的文件长度
 
      if(flen > 0) 
      {
        //以写方式打开文件
             if((filedes = fopen(file, "wb")) == NULL)
             {
                    lr_output_message("打开文件失败!");
               return -1;
               }
  fwrite(lr_eval_string("{pic}"), flen, 1, filedes);   //写入文件内容
  fclose(filedes);    //关闭文件
    }
 
system("D:\\test.bat");
   if((filedes=fopen("D:\\test.txt","rt"))== NULL)
     {
          lr_output_message("打开test.txt文件失败!");
     return -1;
     }  
    
 
fread(result,4,1,filedes);
 
fclose(filedes);  
 
lr_output_message("the velue3 is: %s",result); 
lr_save_string(result,"check");
lr_output_message("the check is %s",lr_eval_string("{check}"));
 
 
 
lr_start_transaction("登录");
 
web_submit_data("userLogin", 
"Action=http://X.X.X.X/Kindergarten/login/userLogin", 
"Method=POST", 
"RecContentType=text/html", 
"Referer=http://X.X.X.X/Kindergarten/login/login", 
"Snapshot=t13.inf", 
"Mode=HTTP", 
ITEMDATA, 
"Name=username", "Value=17715290001", ENDITEM, 
"Name=password", "Value=123456", ENDITEM, 
"Name=code", "Value={check}", ENDITEM, 
LAST); 
lr_end_transaction("登录",LR_AUTO);
 
 
    //验证登录是否成功:登录进去后再提交一次数据交互的请求
lr_start_transaction("修改密码");
     web_submit_data("changePwd", 
"Action=http://X.X.X.X/Kindergarten/sys/changePwd", 
"Method=POST", 
"RecContentType=application/json", 
"Referer=http://X.X.X.X/Kindergarten/sys/changePwdView", 
"Snapshot=t53.inf", 
"Mode=HTTP", 
ITEMDATA, 
"Name=oPwd", "Value=123456", ENDITEM, 
"Name=nPwd", "Value=qwaszx", ENDITEM, 
"Name=nPwd2", "Value=qwaszx", ENDITEM, 
LAST);
 lr_end_transaction("修改密码",LR_AUTO);
 
return 0;
 
}

备注:

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 里面设置,但是因为可能有缓存情况,所以不能根据登录成功后的系统页面来判断是否登录成功,最好是再操作一个数据交互的请求来判断是否登录成功;我的例子是再提交一个修改密码的操作来操作是否登录成功;


              【下面是我整理的2023年最全的软件测试工程师学习知识架构体系图】


一、Python编程入门到精通

二、接口自动化项目实战 

三、Web自动化项目实战


四、App自动化项目实战 

五、一线大厂简历


六、测试开发DevOps体系 

七、常用自动化测试工具

八、JMeter性能测试 

九、总结(尾部小惊喜)

生命不息,奋斗不止。每一份努力都不会被辜负,只要坚持不懈,终究会有回报。珍惜时间,追求梦想。不忘初心,砥砺前行。你的未来,由你掌握!

生命短暂,时间宝贵,我们无法预知未来会发生什么,但我们可以掌握当下。珍惜每一天,努力奋斗,让自己变得更加强大和优秀。坚定信念,执着追求,成功终将属于你!

只有不断地挑战自己,才能不断地超越自己。坚持追求梦想,勇敢前行,你就会发现奋斗的过程是如此美好而值得。相信自己,你一定可以做到! 

最后感谢每一个认真阅读我文章的人,礼尚往来总是要有的,虽然不是什么很值钱的东西,如果你用得到的话可以直接拿走:

这些资料,对于【软件测试】的朋友来说应该是最全面最完整的备战仓库,这个仓库也陪伴上万个测试工程师们走过最艰难的路程,希望也能帮助到你! 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1293990.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

IPC之四:使用 POSIX 消息队列进行进程间通信的实例

IPC 是 Linux 编程中一个重要的概念,IPC 有多种方式,本文主要介绍消息队列(Message Queues),消息队列可以完成同一台计算机上的进程之间的通信,相比较管道,消息队列要复杂一些,但使用起来更加灵活和方便&am…

2023.12.1 --数据仓库之 拉链表

目录 什么是拉链表 为什么要做拉链表? 没使用拉链表: 使用了拉链表: 题中订单拉链表的形成过程 实现语句 什么是拉链表 拉链表是缓慢渐变维的一种解决方案. 拉链表,记录每条信息的生命周期,一旦一条记录的生命周期结束,就重新开始一条新的记录,并把当前日期放入生效开始…

snapde批量手机号码归属地查询

一、引言 手机号码归属地如何查询?在网上一个一个去查询吗?有没有什么软件能够对几万、几十万、上百万的手机号码批量查询出来归属地呢?答案是有,snapde软件能够用一条公式完成表格内所有手机归属地的查询。 二、操作方法 1、打…

Hackademic.RTB1

信息收集 判断存活主机 nmap -sT --min-rate 10000 192.168.182.0/24Nmap scan report for 192.168.182.135 Host is up (0.030s latency). Not shown: 992 filtered tcp ports (no-response), 6 filtered tcp ports (host-unreach) PORT STATE SERVICE 22/tcp closed ssh …

IPTABLES(一)

文章目录 1. iptables基本介绍1.1 什么是防火墙1.2 防火墙种类1.3 iptables介绍1.4 包过滤防火墙1.5 包过滤防火墙如何实现 2. iptables链的概念2.1 什么是链2.2 iptables有哪些链 3. iptables表的概念3.1 什么是表3.2 表的功能3.3 表与链的关系 4. iptables规则管理4.1 什么是…

Spring MVC详解、静态资源访问、拦截器

1. Spring MVC概述 1.1 Spring MVC是什么 SpringMVC是Spring的一个模块,是一个基于MVC设计模式的web框架。 1.2 Spring MVC执行流程。 1.3 组件分析 前端控制器(默认配置)Dispatcher Servlet 作用:只负责分发请求。可以很好的对…

HL7/FHIR 是什么

如果你对上面 2 个单词不熟悉的话,那就需要先脑补下了。 HL7 HL7 可以认为是一个标准化的组织,这个组织主要对标准进行控制。 如果你希望在医疗系统中对数据进行交换,通常 HL7 现在就是事实上的标准了。 FHIR FHIR – Fast Health Inter…

urllib 异常、cookie、handler及代理(四)

目录 一、urllib异常 二、urllib cookie登录 三、urllib handler 处理器的基本使用 四、urllib 代理和代理池 参考 一、urllib异常 URLError/HTTPError 简介: 1.HTTPError类是URLError类的子类 2.导入的包urllib.error.HTTPError urllib.error.URLError 3.h…

JavaScript单页面路由详解:打造现代化、高性能的Web应用

​🌈个人主页:前端青山 🔥系列专栏:JavaScript篇 🔖人终将被年少不可得之物困其一生 依旧青山,本期给大家带来JavaScript篇专栏内容:JavaScript-spa单页面路由 目录 # 基于SPA的单页面路由 关于单页应用 单页应用的…

编程实战:自己编写HTTP服务器(系列2:请求)

系列入口:编程实战:自己编写HTTP服务器(系列1:概述和应答)-CSDN博客 本文介绍如何处理请求。 目录 一、概述 二、成员变量 三、接收并分解请求 四、完整代码 五、HTTP处理框架 一、概述 请求和应答结构其实差不多…

Axure原型图表组件库,数据可视化元件(Axure9大屏组件)

针对Axure制作的大屏图表元件库,帮助产品经理更高效地制作高保真图表原型,是产品经理必备元件工具。现分享完整的组件库,大家一起学习。 本组件库的图表模块,已包含所有常用的图表,以下为部分组件截图示意。文末可下载…

Axure原型组件库,数据可视化动态元件库(超详细Axure9可视化素材)

专门针对Axure制作的动态图表元件库,帮助产品经理更高效地制作高保真图表原型,是产品经理必备元件工具。现分享完整 Axure 9 的组件库,大家一起学习。(如需 Axure 8组件请详见文末) 每一个动态组件在原型文件中都配有…

NLP自然语言处理学习笔记

参考:NLP(自然语言处理)介绍 - 知乎 (zhihu.com) 一、NLP是什么 自然语言处理( Natural Language Processing, NLP)是计算机科学领域与人工智能领域中的一个重要方向。它研究能实现人与计算机之间用自然语言进行有效通信的各种理论和方法。自…

小航助学2023年6月GESP_Scratch二级真题(含题库答题软件账号)

需要在线模拟训练的题库账号请点击 小航助学编程在线模拟试卷系统(含题库答题软件账号 单选题3.00分 删除编辑附件图文 答案:D 第1题高级语言编写的程序需要经过以下( )操作,可以生成在计算机上运行的可执行代码。 A、编辑B、…

Liunx系统使用超详细(四)~文件/文本相关命令2

承接文章Liunx系统使用超详细(四)~文件/文本相关命令1http://t.csdnimg.cn/f7G6S 目录 一、awk命令(三剑客之一) 1.1工作原理 1.2工作流程 1.3语法格式 1.3.1格式注释: 1.3.2模式(pattern)的类型: 1.3.3动作(ac…

Java期末复习题之继承

点击返回标题->23年Java期末复习-CSDN博客 第1题. 设计一个学生类Student,其数据成员有name(姓名)、age(年龄)和degree(学位)。由Student类派生出本科生类Undergraduate和研究生类Graduate,本科生类Undergraduate增加成员specialty(专业),…

vue-tree-color 组件实现组织架构图遇到的坑和解决方案以及实现

**1、前期工作可以先看看大佬的文章 **https://blog.csdn.net/Try_your_best_l/article/details/120173192?spm1001.2101.3001.6650.5&utm_mediumdistribute.pc_relevant.none-task-blog-2defaultCTRLISTRate-5-120173192-blog-128109597.235%5Ev38%5Epc_relevant_default…

案例精选|聚铭网络助力莱阳市人民医院打造合规性网络安全保障体系

莱阳市人民医院是一所集医疗、教学、科研、急救、康复、医养结合于一体的大型二级甲等综合性公立医院,占地总面积约3万平方米,建筑面积约7万平方米,设置科室48个,开放床位500张。医院先后获得山东省首批医养结合典型、山东省卒中防…

案例060:基于微信小程序考试系统

文末获取源码 开发语言:Java 框架:SSM JDK版本:JDK1.8 数据库:mysql 5.7 开发软件:eclipse/myeclipse/idea Maven包:Maven3.5.4 小程序框架:uniapp 小程序开发软件:HBuilder X 小程序…

学习设计模式的一个好网址

常用设计模式有哪些? (refactoringguru.cn)https://refactoringguru.cn/design-patterns