使用SoapUI进行接口自动化测试和持续集成的参数化方法
按照自动化测试分层实现的原理,每一层的脚本实现都要进行参数化,自动化的目标就是要实现脚本代码与测试数据分离。
当测试数据进行调整的时候不会对脚本的实现带来震荡,从而提高脚本的稳定性与灵活度,降低脚本的维护成本。
Soapui最为强大的参数化就是支持groovy脚本的参数化或者java代码,任何无法实现的地方都可以考虑脚本的扩展。
1.Soapui的常用参数化类型
2.Soapui参数化操作方式
菜单路径:Test Steps->Add Step(右键菜单)->Data Source
3.Txt 文件参数化
-
在脚本中参数化
-
新建txt文件
-
文件内容
数据之间要用逗号做分隔符,否则soapui没办法区分数据
-
选择数据源类型与文件
1.增加参数
2.选择数据类型
3.选择数据文件
4.数据的分隔符
image.png
4.Excel文件参数化
-
新建excel文件
-
编辑文件内容
-
选择数据源类型与文件
1.增加参数
2.选择数据类型
3.选择数据文件
4.起始单元格
5.Groovy脚本参数化
groovy是基于java语言的脚本语 言,语法结构与java雷同,或者直接写java代码也是可以的
-
假设我们要通过接口创建客户
要求:姓名,手机号码,email不能重复
1.随机生成姓名的代码
public List<String> RandomUserName(int RandomUserName) {
String[] FirstName = ["赵","钱", "孙", "李", "周", "吴", "郑", "王", "冯", "陈", "褚", "卫", "蒋", "沈", "韩", "杨", "朱", "秦", "尤", "许",
"何", "吕", "施", "张", "孔", "曹", "严", "华", "金", "魏", "陶", "姜", "戚", "谢", "邹", "喻", "柏", "水", "窦", "章", "云", "苏", "潘", "葛", "奚", "范", "彭", "郎",
"鲁", "韦", "昌", "马", "苗", "凤", "花", "方", "俞", "任", "袁", "柳", "酆", "鲍", "史", "唐", "费", "廉", "岑", "薛", "雷", "贺", "倪", "汤", "滕", "殷"];
List<String> randomName = new ArrayList<>();
for (int i = 1; i <= RandomUserName; i++) {
Random randomFirstName = new Random();
int index = randomFirstName.nextInt(FirstName.length - 1);
String name = FirstName[index];
if(randomFirstName.nextBoolean()){
name += getChinese()+getChinese();
randomName.add(name);
}
else{
name += getChinese();
randomName.add(name);
}
}
return randomName;
}
public static String getChinese() {
String str = null;
int highPos, lowPos;
Random randomChinese = new Random();
highPos = (176 + Math.abs(randomChinese.nextInt(55)))
randomChinese = new Random();
lowPos = 161 + Math.abs(randomChinese.nextInt(94))
byte[] bArr = new byte[2];
bArr[0] = (new Integer(highPos)).byteValue();
bArr[1] = (new Integer(lowPos)).byteValue();
try {
str = new String(bArr, "GB2312");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return str;
}
2.随机生成手机号的代码
public List<String> RandomTelNum(int RandomTel) {
List<String> RandomTelNum = new ArrayList<>();
for (int i = 0; i < RandomTel; i++) {
String TelNumHead = "170";
int min = 10000000;
int max = 99999999;
Random randomTelLast = new Random();
int s = randomTelLast.nextInt(max) % (max - min + 1) + min;
String telNum = TelNumHead + Integer.toString(s);
RandomTelNum.add(telNum);
}
return RandomTelNum;
}
3.随机生成Email的代码
public List<String> RandomEmail(int RandomEmail) {
List<String> randomEmail = new ArrayList<>();
for (int i = 0; i < RandomEmail; i++) {
String[] randomName = "ab,bc,cd,de,ef,fg,gh,hi,ij,jk,kl,lm,mn,no,op,pq,qr,rs,st,tu,uv,vw,wx,xy,yz,za".split(",");
Random randomletter = new Random();
int index = randomletter.nextInt(26);
String EmailName = randomName[index] +randomName[index/3]+ System.currentTimeMillis();
EmailName += getemail_suffix();
randomEmail.add(EmailName);
}
return randomEmail;
}
public static String getemail_suffix() {
String[] email_suffix = "@gmail.com,@yahoo.com,@msn.com,@hotmail.com,@aol.com,@ask.com,@live.com,@qq.com,@0355.net,@163.com,@163.net,@263.net,@3721.net,@yeah.net,@googlemail.com,@126.com,@sina.com,@sohu.com,@yahoo.com.cn".split(",");
String str;
Random randomEmail_suffix = new Random();
int index = randomEmail_suffix.nextInt(email_suffix.length - 1);
str = email_suffix[index];
return str;
}
运行的效果
-
代码产生的数据与变量关联
//随机生成姓名
println(RandomUserName(1)[0]);
//代码产生的数据与变量关联
result["name"]=RandomUserName(1)[0]
//随机生成邮箱
println(RandomEmail(1)[0]);
//代码产生的数据与变量关联
result["email"]=RandomEmail(1)[0]
//随机生成手机号码
println(RandomTelNum(1)[0]);
//代码产生的数据与变量关联
result["mobile"]=RandomTelNum(1)[0]
6.JDBC参数化
当接口产生的数据需要从数据库读取的时候我们可以连接数据对数据查询进行数据关联,soapui是可以链接多种数据库,我们使用mysql做演示
-
mysql驱动配置
1.下载mysql驱动的jar包
http://pan.baidu.com/s/1ge5BLhL
2.拷贝驱动jar到如下路径(soapui的安装路径)
C:\Program Files\SmartBear\SoapUI-Pro-5.1.2\jre\lib\ext
配置数据源
数据库连接成功,说明数据源已经配置好
-
编辑SQL
select userName,passWord from user
7.参数关联到Request
这一步虽然比较简单,但是至关重要,否则参数化是体现不出来的
最后感谢每一个认真阅读我文章的人,礼尚往来总是要有的,虽然不是什么很值钱的东西,如果你用得到的话可以直接拿走:
这些资料,对于【软件测试】的朋友来说应该是最全面最完整的备战仓库,这个仓库也陪伴上万个测试工程师们走过最艰难的路程,希望也能帮助到你!
推荐阅读
-
如何使用 Java 中的自动化测试工具实施持续集成和自动化测试?
-
纯干货分享 | 研发效能提升——敏捷需求篇-而敏捷需求是提升效能的方式中不可或缺的模块之一。 云智慧的敏捷教练——Iris Xu近期在公司做了一场分享,主题为「敏捷需求挖掘和组织方法,交付更高业务价值的产品」。Iris具有丰富的团队敏捷转型实施经验,完成了企业多个团队从传统模式到敏捷转型的落地和实施,积淀了很多的经验。 这次分享主要包含以下2个部分: 第一部分是用户影响地图 第二部分是事件驱动的业务分析Event driven business analysis(以下简称EDBA) 用户影响地图,是一种从业务目标到产品需求映射的需求挖掘和组织的方法。 在软件开发过程中可能会遇到一些问题,比如大家使用不同的业务语言、技术语言,造成角色间的沟通阻碍,还会导致一些问题,比如需求误解、需求传递错误等;这会直接导致产品的功能需求和要实现的业务目标不是映射关系。 但在交付期间,研发人员必须要将这些需求实现交付,他们实则并不清楚这些功能需求产生的原因是什么、要解决客户的哪些痛点。研发人员往往只是拿到了解决方案,需要把它实现,但没有和业务侧一起去思考解决方案是否正确,能否真正的帮助客户解决问题。而用户影响地图通常是能够连接业务目标和产品功能的一种手段。 我们在每次迭代里加入的假设,也就是功能需求。首先把它先实现,再逐步去验证我们每一个小目标是否已经实现,再看下一个目标要是什么。那影响地图就是在这个过程中帮我们不断地去梳理目标和功能之间的关系。 我们在软件开发中可能存在的一些问题 针对这些问题,我们如何避免?先简单介绍做敏捷转型的常规思路: 先做团队级的敏捷,首先把产品、开发、测试人员,还有一些更后端的人员比如交互运维的同学放在一起,组成一个特训团队做交付。这个团队要包含交付过程中所涉及的所有角色。 接着业务敏捷要打通整个业务环节和研发侧的一个交付。上图中可以看到在敏捷中需求是分层管理的,第一层是业务需求,在这个层级是以用户目标和业务目标作为输入进行规划,同时需要去考虑客户的诉求。业务人员通过获取到的业务需求,进一步的和团队一起将其分解为产品需求。所以业务需求其实是我们真正去发布和运营的单元,它可以被独立发布到我们的生产环境上。我们的产品需求其实就是产品的具体功能,它是我们集成和测试的对象,也就是我们最终去部署到系统上的一个基本单元。产品需求再到了我们的开发团队,映射到迭代计划会上要把它分解为相应的技术任务,包括我们平时所说的比如一些前端的开发、后端的开发、测试都是相应的技术任务。所以业务敏捷要达到的目标是需要去持续顺畅高质量的交付业务价值。 将这几个点串起来,形成金字塔结构。最上层我们会把业务目标放在整个金字塔的塔尖。这个业务目标是通过用户的目标以及北极星指标确立的。确认业务目标后再去梳理相应的业务流程,最后生产。另外产品需求包含了操作流程和业务规则,具需求交付时间、工程时间以及我们的一些质量标准的要求。 谈到用户影响的地图,在敏捷江湖上其实有一个传说,大家都有一个说法叫做敏捷需求的“任督二脉”。用户影响地图其实就是任脉,在黑客马拉松上用过的用户故事地图其实叫督脉。所以说用户影响地图是在用户故事地图之前,先帮我们去梳理出我们要做哪些东西。当我们真正识别出我们要实现的业务活动之后,用户故事地图才去梳理我们整个的业务工作流,以及每个工作流节点下所要包含的具体功能和用户故事。所以说用户影响地图需要解决的问题,我们包括以下这些: 首先是范围蔓延,我们在整张地图上,功能和对应的业务目标是要去有一个映射的。这就避免了一些在我们比如有很多干系人参与的会议上,那大家都有不同想法些立场,会提出很多需求(正确以及错误的需求)。这个时候我们会依据目标去看这些需求是否真的是会影响我们的目标。 这里提到的错误需求,比如是利益相关的人提出的、客户认为产品应该有的、某个产品经理需求分析师认为可以有的....但是这些功能在用户影响地图中匹配不到对应目标的话,就需要降低优先级或弃掉。另外,通常我们去制定解决方案的时候,会考虑较完美的实现,导致解决方案括很多的功能。这个时候关键目标至关重要,会帮助我们梳理筛选、确定优先级。 看一下用户影响到地图概貌 总共分为一个三层的结构: 第一层why,你的业务目标哪个是最重要的,为什么?涉及到的角色有哪些? 第二层how ,怎样产生影响?影响用户角色什么样的行为? (不需要去列出所有的影响,基于业务目标) 第三层what,最关键的是在梳理需求时不需一次把所有细节想全,这通常团队中经常遇到的问题。 我们用这个例子来看一下 这是一个客服中心的影响地图,业务目标是 3个月内不增加客服人数的前提下能支持1.5倍的用户数。此业务目标设定是符合 smart 原则的,specific非常的具体,miserable 是可以衡量的,action reoriented是面向活动的, real list 也是很实际的。 量化的目标会指引我们接下来的行动,梳理一个业务目标,尽量去量化,比如 :我们通过打造一条什么样的流水线,能够提高整个部署的效率,时间是原来的 1/2 。这样才是一个能量化的有意义的目标。 回到这幅图, how 层级识别出来的内容,客服角色:想要对它施加的影响,把客户引导到论坛上,帮助客户更容易的跟踪问题,更快速的去定位问题。初级用户:方论坛上找到问题。高级用户:在论坛上回答问题。通过我们这些用户角色,进行活动,完成在不增加客户客服人数的前提下支持更多的用户数量。 最后一个层级,才是我们日常接触比较多的真正的功能的特性和需求,比如引导到客户到论坛上,其实这个产品就需要有一个常见问题的论坛的链接。这个层次需要我们团队进一步地在交付,在每个迭代之前做进一步的梳理,细化成相应的用户故事。 这个是云智慧团队中,自己做的影响地图的范例,可以看下整个的层级结构。序号表示优先级。 那我们用户影响地图可以总结为:
-
腾讯视频直播 02-推流-美颜滤镜 同样,腾讯云提供了 setBeautyFilter 方法来设置美颜风格、磨皮程度、美白程度和泛红程度 //style 磨皮风格:0:平滑 1:自然 2:朦胧 //美容级别:0-9。值为 0 时关闭美颜效果。默认值:0,关闭美颜效果。 //美白级别:取值 0-9。值为 0 时,将关闭美白效果。默认值:0,关闭美白效果。 //ruddyLevel:取值范围为 0-9。值为 0 时关闭美白效果。默认值:0,关闭美白效果。 public boolean setBeautyFilter(int style, int beautyLevel, int whiteningLevel, int ruddyLevel);; public boolean setBeautyFilter(int style, int beautyLevel, int whiteningLevel, int ruddyLevel) 滤镜 setFilter 方法可以设置滤镜效果,滤镜本身是一个直方图文件。setSpecialRatio 方法可以设置滤镜的程度,从 0 到 1,越大滤镜效果越明显,默认值为 0.5。 Bitmap bitmap = BitmapUtils.decodeResource(getResources, R.drawable.langman); if (mLivePusher) if (mLivePusher ! = null) { mLivePusher.setFilter(bmp); } 控制摄像头 腾讯云 sdk 默认为前置摄像头(可以通过修改 TXLivePushConfig 的配置函数 setFrontCamera 来修改默认值),调用一次 switchCamera 就切换一次,注意切换摄像头前要确保 TXLivePushConfig 和 TXLivePusher 对象已经初始化。 mLivePushConfig.setFrontCamera(true); // 默认前置摄像头。 mLivePusher.switchCamera; //切换摄像头。 ⑦ 设置徽标水印 腾讯视频云目前支持两种设置水印的方式:一种是在流媒体 SDK 中设置水印,原理是在 SDK 中对视频进行编码前在画面中设置水印。另一种方式是在云端设置水印,即由云端解析视频并添加水印标识。 建议使用 SDK 添加水印,因为在云端添加水印会有问题。下面是添加水印的 SDK 介绍: //设置视频水印 mLivePushConfig.setWatermark(BitmapFactory.decodeResource(getResources,R.drawable.watermark), 10, 10); // 最后两个参数是视频的水印。 //最后两个参数是水印位置的 X 轴和 Y 轴坐标。 mLivePusher.setConfig(mLivePushConfig); 如果需要对水印图像的位置进行模型适配,则需要调用水印规范化接口。 /设置视频水印 mLivePushConfig.setWatermark(mBitmap, 0.02f, 0.05f, 0.2f); //参数为水印图像。 //参数包括水印图像的位图、水印位置的 X 轴坐标、水印位置的 Y 轴坐标和水印宽度。后三个参数的范围是 [0,1]。 // 最后两个参数是水印位置的 X 轴坐标和 Y 轴坐标。 mLivePusher.setConfig(mLivePushConfig); TXLivePushConfig 中的 setHardwareAcceleration 方法可以启用或禁用硬件编码。 if (mHWVideoEncode){ if (mLivePushConfig ! = null) { if (Build.VERSION.SDK_INT < 18){ Toast.makeText(getApplicationContext, "Hardware acceleration failed, current phone API level is too low (min 18)"、 Toast.LENGTH_SHORT).show; mHWVideoEncode = false; } } } } mLivePushConfig.setHardwareAcceleration(mHWVideoEncode ? TXLiveConstants.ENCODE_VIDEO_HARDWARE : TXLiveConstants.ENCODE_VIDEO_SOFTWARE); mLivePusher.setConfig(mLivePushConfig); // 如果您不确定何时启用硬件加速,建议将其设置为 ENCODE_VIDEO_AUTO。 // 默认情况下启用软件编码,但如果手机的 CPU 使用率超过 80% 或帧速率为 10,SDK 将自动切换到硬件编码。 ⑨ 后台推流 在常规模式下,一旦应用程序进入后台,摄像头捕捉数据的能力就会被 Android 禁用,这意味着 SDK 无法继续捕捉和编码音频和视频数据。如果我们什么都不做,故事就会按照下面的脚本发展: 阶段 1(背景剪切后 10 秒 ->)- CDN 无法将视频流传输给观众,因为没有数据,观众看到的是主帧。 阶段 2(10 秒-> 70 秒)--观众一方的播放器因无法接收到直播流而退出,房间里空无一人。 第 3 阶段(70 秒后)--服务器直接断开了推送流媒体的 RTMP 链接,主播需要重新打开直播才能继续。 主播可能只是短暂地接了一个紧急电话,但各云提供商的安全措施会迫使主播的直播提前结束。 1) 设置 setPauseFlag 在开始推流之前,使用 TXLivePushConfig 的 setPauseImg 接口设置一个等待图像,其含义建议为 "主播将暂时离开,稍后再回来"。
-
使用SoapUI进行接口自动化测试和持续集成的参数化方法
-
【Netty】「萌新入门」(七)ByteBuf 的性能优化-堆内存的分配和释放都是由 Java 虚拟机自动管理的,这意味着它们可以快速地被分配和释放,但是也会产生一些开销。 直接内存需要手动分配和释放,因为它由操作系统管理,这使得分配和释放的速度更快,但是也需要更多的系统资源。 另外,直接内存可以映射到本地文件中,这对于需要频繁读写文件的应用程序非常有用。 此外,直接内存还可以避免在使用 NIO 进行网络传输时发生数据拷贝的情况。在使用传统的 I/O 时,数据必须先从文件或网络中读取到堆内存中,然后再从堆内存中复制到直接缓冲区中,最后再通过 SocketChannel 发送到网络中。而使用直接缓冲区时,数据可以直接从文件或网络中读取到直接缓冲区中,并且可以直接从直接缓冲区中发送到网络中,避免了不必要的数据拷贝和内存分配。 通过 ByteBufAllocator.DEFAULT.directBuffer 方法来创建基于直接内存的 ByteBuf: ByteBuf directBuf = ByteBufAllocator.DEFAULT.directBuffer(16); 通过 ByteBufAllocator.DEFAULT.heapBuffer 方法来创建基于堆内存的 ByteBuf: ByteBuf heapBuf = ByteBufAllocator.DEFAULT.heapBuffer(16); 注意: 直接内存是一种特殊的内存分配方式,可以通过在堆外申请内存来避免 JVM 堆内存的限制,从而提高读写性能和降低 GC 压力。但是,直接内存的创建和销毁代价昂贵,因此需要慎重使用。 此外,由于直接内存不受 JVM 垃圾回收的管理,我们需要主动释放这部分内存,否则会造成内存泄漏。通常情况下,可以使用 ByteBuffer.clear 方法来释放直接内存中的数据,或者使用 ByteBuffer.cleaner 方法来手动释放直接内存空间。 测试代码: public static void testCreateByteBuf { ByteBuf buf = ByteBufAllocator.DEFAULT.buffer(16); System.out.println(buf.getClass); ByteBuf heapBuf = ByteBufAllocator.DEFAULT.heapBuffer(16); System.out.println(heapBuf.getClass); ByteBuf directBuf = ByteBufAllocator.DEFAULT.directBuffer(16); System.out.println(directBuf.getClass); } 运行结果: class io.netty.buffer.PooledUnsafeDirectByteBuf class io.netty.buffer.PooledUnsafeHeapByteBuf class io.netty.buffer.PooledUnsafeDirectByteBuf 池化技术 在 Netty 中,池化技术指的是通过对象池来重用已经创建的对象,从而避免了频繁地创建和销毁对象,这种技术可以提高系统的性能和可伸缩性。 通过设置 VM options,来决定池化功能是否开启: -Dio.netty.allocator.type={unpooled|pooled} 在 Netty 4.1 版本以后,非 Android 平台默认启用池化实现,Android 平台启用非池化实现; 这里我们使用非池化功能进行测试,依旧使用的是上面的测试代码 testCreateByteBuf,运行结果如下所示: class io.netty.buffer.UnpooledByteBufAllocator$InstrumentedUnpooledUnsafeDirectByteBuf class io.netty.buffer.UnpooledByteBufAllocator$InstrumentedUnpooledUnsafeHeapByteBuf class io.netty.buffer.UnpooledByteBufAllocator$InstrumentedUnpooledUnsafeDirectByteBuf 可以看到,ByteBuf 类由 PooledUnsafeDirectByteBuf 变成了 UnpooledUnsafeDirectByteBuf; 在没有池化的情况下,每次使用都需要创建新的 ByteBuf 实例,这个操作会涉及到内存的分配和初始化,如果是直接内存则代价更为昂贵,而且频繁的内存分配也可能导致内存碎片问题,增加 GC 压力。 使用池化技术可以避免频繁内存分配带来的开销,并且重用池中的 ByteBuf 实例,减少了内存占用和内存碎片问题。另外,池化技术还可以采用类似 jemalloc 的内存分配算法,进一步提升分配效率。 在高并发环境下,池化技术的优点更加明显,因为内存的分配和释放都是比较耗时的操作,频繁的内存分配和释放会导致系统性能下降,甚至可能出现内存溢出的风险。使用池化技术可以将内存分配和释放的操作集中到预先分配的池中,从而有效地降低系统的内存开销和风险。 内存释放 当在 Netty 中使用 ByteBuf 来处理数据时,需要特别注意内存回收问题。 Netty 提供了不同类型的 ByteBuf 实现,包括堆内存(JVM 内存)实现 UnpooledHeapByteBuf 和堆外内存(直接内存)实现 UnpooledDirectByteBuf,以及池化技术实现的 PooledByteBuf 及其子类。 UnpooledHeapByteBuf:通过 Java 的垃圾回收机制来自动回收内存; UnpooledDirectByteBuf:由于 JVM 的垃圾回收机制无法管理这些内存,因此需要手动调用 release 方法来释放内存; PooledByteBuf:使用了池化机制,需要更复杂的规则来回收内存; 由于池化技术的特殊性质,释放 PooledByteBuf 对象所使用的内存并不是立即被回收的,而是被放入一个内存池中,待下次分配内存时再次使用。因此,释放 PooledByteBuf 对象的内存可能会延迟到后续的某个时间点。为了避免内存泄漏和占用过多内存,我们需要根据实际情况来设置池化技术的相关参数,以便及时回收内存; Netty 采用了引用计数法来控制 ByteBuf 对象的内存回收,在博文 「源码解析」ByteBuf 的引用计数机制 中将会通过解读源码的形式对 ByteBuf 的引用计数法进行深入理解; 每个 ByteBuf 对象被创建时,都会初始化为1,表示该对象的初始计数为1。 在使用 ByteBuf 对象过程中,如果当前 handler 已经使用完该对象,需要通过调用 release 方法将计数减1,当计数为0时,底层内存会被回收,该对象也就被销毁了。此时即使 ByteBuf 对象还在,其各个方法均无法正常使用。 但是,如果当前 handler 还需要继续使用该对象,可以通过调用 retain 方法将计数加1,这样即使其他 handler 已经调用了 release 方法,该对象的内存仍然不会被回收。这种机制可以有效地避免了内存泄漏和意外访问已经释放的内存的情况。 一般来说,应该尽可能地保证 retain 和 release 方法成对出现,以确保计数正确。