使用robotframework做接口测试5——一个用例中调多个接口

RF教程雪霁 发表了文章 • 20 个评论 • 5345 次浏览 • 2017-05-15 13:48 • 来自相关话题

凡是涉及一点点有接口关联的,都可能下一个接口需要上一个接口的某个返回值作为入参,最直接的例子,就是登录依赖。用接口做业务性的测试,也绝对离不开接口依赖的,业务都是一系列接口串联的结果,有时候一个接口操作的结果,也需另外的接口验证,举几个例子,以某个文章的评论用例为例,我们选取几个评论的冒烟用例来看看吧。
拉取评论列表(list接口)增加一条评论(add接口)将评论置顶及取消置顶(stick接口)删除评论(delete接口)

用例1很简单,仅是个数据读接口没有做写操作,做一些基本的响应校验就OK了,这个接口不在我们的讨论范围。
再看用例2,增加评论是有个写操作的,对于这一操作,如果用手工测试,完整校验点应该是,1)增加评论成功  2)增加的这条评论在评论列表里(且在第一位,考虑到有置顶情况,那就在第2位),所以,这里的最基本的校验点涉及两个接口,第1个接口(add接口)依赖第2个接口(list接口)做校验。事实上,这个评论id还需给其他接口使用,以达到数据清理及重复利用的效果,这个也不在本文的讨论范围。

当然,这些接口,还有个更全局的依赖,用户登录。用户登录的依赖在之前的文章已经有提到过,放在suite setup里是不错的选择:接口登录保持
既然是需要一个用例里面有多个接口,我们希望代码越少越好,最好是一行解决一个接口。这是反向思维,正向的思维是:接口类型固定时,总是有规律可循的,所以当很多很多代码开始重复时,我们要抽取成一个比较通用的关键字,以达到精简用例的效果,用例清晰明了,写起来也简单,扩展容易,维护工作量异常小。这有点像代码重构的思想。

接口测试用一句话概括就是,用什么样的测试数据,测哪个接口,得到的怎样的响应。重点明确了,用例中,接口的基本要素只有1、待测接口  2、待测接口的入参  3、响应数据。一个关键字如果满足了这些要素,也就能达到我们想要的效果。
来看一例:





在此用例中,mobile_post关键字将一些接口调用的细节全都掩盖掉了,其中包括但不限于:
请求的host及一些固定的参数接口入参反向update到入参模板里接口数字签名目标返回值的分拆及获取
该关键字的必需参数只有1、待测接口名 和 2、待测接口入参,其他一些只做为可选参数,有更多的输入自由,也使得关键字的可重用性更高。然后,一个接口就一行脚本,断言在关键字外做,也是为了提高写用例的灵活性。实践证明,使用这个关键字后,写用例速度明显提高了。该关键字中用到的更底层关键字,也尽量用rf的关键字在写,rf的日志打印比较好,遇到问题方便日志追踪。
 
 
这里重点讲一下接口的入参模板:
1、为什么要有入参模板
百度结果中有好多告诉你怎么用rf做接口测试的文章,如何创建session,如何用create dictionary关键字构建测试数据,如何传header,如何做一个post接口,如何做一个get接口。——那只是个demo
我们做自动化时是在做工程,不是在做demo,也就是那些解释性的脚本,底层一步一步怎么实现的(header怎么传,data怎么拼接,该用post还是get),已经不再是重点,我们更应该关注的,是用例本身,怎么写用例能更好的覆盖到验证点,怎么处理测试数据,怎么写好可维护性的用例,怎么去组织好用例结构,套件结构,工程结构,怎么让用例有更好的环境(测试,预发,生产)移植性。
扯远了,回到入参模板。实际中,单单一个接口的入参就多得不敢想象,十几个,或更多,某个用例中这十几个入参实际起作用的也许就3-4个。有些接口其实也不止一层json那么简单,也有某个字段有多层结构的。这个时候,最好是有个模板,模板大概长这样:
           接口A:{key1:value1, key2:value2}   #接口A及其入参
           接口B:{key3:value3, key4:value4, key5:value5, key6:value6}
           接口C:{key7:value7, key8:{Key81:value81}, key9:[value91, value92, value93]}
           ...
 2、入参模板rf中怎么实现

参考了一些其他做接口测试的同仁,有用数据库实现的,也有用初始化配置文件的。rf在这方面考虑还是蛮齐全,我用的是py变量文件vars.py,当配置文件用,另外可能还需要有一个辅助的py关键字文件common.py。

1)大致长这样的vars.pyMOBILE_DEFAULT_VALUE={
#comment
"comment.add":{"v":"1.0","data":{"articleid":"1","content":u"大盘啥时候能好起来我就给好评","targetid":"","commentid":"",,"uid":"1"}}, #增加文章评论接口
"comment.list":{"v":"2.0","data":{"articleid":"","cursor":"-1","count":"20"}}, #获取文章评论列表
"comment.delete":{"v":"1.0","data":{"commentid":"","uid":""}}#删除评论
}2)大致长这样的common.py# -*- coding:utf-8 -*-import vars

def mobile_paras(apiName,dataStr='{}'):
'''
参数:待测接口名apiName 待测接口入参 dataStr
示例: ${return} | mobile_paras | user/sms | {"phone":"66666666"}
返回:接口版本号 及最终入参
'''
try:
datadict = vars.MOBILE_DEFAULT_VALUE[apiName]['data']
apiVersion = vars.MOBILE_DEFAULT_VALUE[apiName]['v']
except KeyError:
print u"不存在的api名,请重新输入"

if dataStr == '':
dataStr = '{}'

dataNew = eval(dataStr)
datadictCopy = datadict.copy()
datadictCopy.update(dataNew)#这句是关键,把数据update到模板取到的data中去

return [apiVersion,datadictCopy]分离变量文件和关键字文件是rf的规定,也是个好的编码习惯,以后vars.py中还要扩展其他更多更多的变量,当然common.py中也不可避免增加一些rf不擅长但python擅长处理的关键字。

3)大致长这样的mobile_post关键字:
最后,用一个rf的关键字,把一些关键数据组一组,该签名的签名,该登录的登录,该返回的返回:





再回到第1张图,待测接口comment.add,目标待传参数in_data为{"articleid":"3215","content":"大盘啥时候能好起来我就给好评","targetid":"","commentid":"","uid":"101123"},用例传参{"articleid":"3215","uid":"101123"},其他参数在模板中已默认,实际传参如目标待传。
 
4)结构:
 vars.py及common.py放同一级目录,以如下方式导入含有mobile_post的resource文件中





以上,仅提供思路。有些同学的接口入参及调用都很简单,3行内可以搞定一个接口,也可不必做得这么麻烦。在工程化的道路上,只有实践出来的路才是最好的路。

有更好的思路欢迎分享在评论~
  查看全部
凡是涉及一点点有接口关联的,都可能下一个接口需要上一个接口的某个返回值作为入参,最直接的例子,就是登录依赖。用接口做业务性的测试,也绝对离不开接口依赖的,业务都是一系列接口串联的结果,有时候一个接口操作的结果,也需另外的接口验证,举几个例子,以某个文章的评论用例为例,我们选取几个评论的冒烟用例来看看吧。
  1. 拉取评论列表(list接口)
  2. 增加一条评论(add接口)
  3. 将评论置顶及取消置顶(stick接口)
  4. 删除评论(delete接口)


用例1很简单,仅是个数据读接口没有做写操作,做一些基本的响应校验就OK了,这个接口不在我们的讨论范围。
再看用例2,增加评论是有个写操作的,对于这一操作,如果用手工测试,完整校验点应该是,1)增加评论成功  2)增加的这条评论在评论列表里(且在第一位,考虑到有置顶情况,那就在第2位),所以,这里的最基本的校验点涉及两个接口,第1个接口(add接口)依赖第2个接口(list接口)做校验。事实上,这个评论id还需给其他接口使用,以达到数据清理及重复利用的效果,这个也不在本文的讨论范围。

当然,这些接口,还有个更全局的依赖,用户登录。用户登录的依赖在之前的文章已经有提到过,放在suite setup里是不错的选择:接口登录保持
既然是需要一个用例里面有多个接口,我们希望代码越少越好,最好是一行解决一个接口。这是反向思维,正向的思维是:接口类型固定时,总是有规律可循的,所以当很多很多代码开始重复时,我们要抽取成一个比较通用的关键字,以达到精简用例的效果,用例清晰明了,写起来也简单,扩展容易,维护工作量异常小。这有点像代码重构的思想。

接口测试用一句话概括就是,用什么样的测试数据,测哪个接口,得到的怎样的响应。重点明确了,用例中,接口的基本要素只有1、待测接口  2、待测接口的入参  3、响应数据。一个关键字如果满足了这些要素,也就能达到我们想要的效果。
来看一例:

简写post1.png

在此用例中,mobile_post关键字将一些接口调用的细节全都掩盖掉了,其中包括但不限于:
  • 请求的host及一些固定的参数
  • 接口入参反向update到入参模板里
  • 接口数字签名
  • 目标返回值的分拆及获取

该关键字的必需参数只有1、待测接口名 和 2、待测接口入参,其他一些只做为可选参数,有更多的输入自由,也使得关键字的可重用性更高。然后,一个接口就一行脚本,断言在关键字外做,也是为了提高写用例的灵活性。实践证明,使用这个关键字后,写用例速度明显提高了。该关键字中用到的更底层关键字,也尽量用rf的关键字在写,rf的日志打印比较好,遇到问题方便日志追踪。
 
 
这里重点讲一下接口的入参模板:
1、为什么要有入参模板
百度结果中有好多告诉你怎么用rf做接口测试的文章,如何创建session,如何用create dictionary关键字构建测试数据,如何传header,如何做一个post接口,如何做一个get接口。——那只是个demo
我们做自动化时是在做工程,不是在做demo,也就是那些解释性的脚本,底层一步一步怎么实现的(header怎么传,data怎么拼接,该用post还是get),已经不再是重点,我们更应该关注的,是用例本身,怎么写用例能更好的覆盖到验证点,怎么处理测试数据,怎么写好可维护性的用例,怎么去组织好用例结构,套件结构,工程结构,怎么让用例有更好的环境(测试,预发,生产)移植性。
扯远了,回到入参模板。实际中,单单一个接口的入参就多得不敢想象,十几个,或更多,某个用例中这十几个入参实际起作用的也许就3-4个。有些接口其实也不止一层json那么简单,也有某个字段有多层结构的。这个时候,最好是有个模板,模板大概长这样:
           接口A:{key1:value1, key2:value2}   #接口A及其入参
           接口B:{key3:value3, key4:value4, key5:value5, key6:value6}
           接口C:{key7:value7, key8:{Key81:value81}, key9:[value91, value92, value93]}
           ...
 2、入参模板rf中怎么实现

参考了一些其他做接口测试的同仁,有用数据库实现的,也有用初始化配置文件的。rf在这方面考虑还是蛮齐全,我用的是py变量文件vars.py,当配置文件用,另外可能还需要有一个辅助的py关键字文件common.py。

1)大致长这样的vars.py
MOBILE_DEFAULT_VALUE={
#comment
"comment.add":{"v":"1.0","data":{"articleid":"1","content":u"大盘啥时候能好起来我就给好评","targetid":"","commentid":"",,"uid":"1"}}, #增加文章评论接口
"comment.list":{"v":"2.0","data":{"articleid":"","cursor":"-1","count":"20"}}, #获取文章评论列表
"comment.delete":{"v":"1.0","data":{"commentid":"","uid":""}}#删除评论
}
2)大致长这样的common.py
# -*- coding:utf-8 -*-
import vars

def mobile_paras(apiName,dataStr='{}'):
'''
参数:待测接口名apiName 待测接口入参 dataStr
示例: ${return} | mobile_paras | user/sms | {"phone":"66666666"}
返回:接口版本号 及最终入参
'''
try:
datadict = vars.MOBILE_DEFAULT_VALUE[apiName]['data']
apiVersion = vars.MOBILE_DEFAULT_VALUE[apiName]['v']
except KeyError:
print u"不存在的api名,请重新输入"

if dataStr == '':
dataStr = '{}'

dataNew = eval(dataStr)
datadictCopy = datadict.copy()
datadictCopy.update(dataNew)#这句是关键,把数据update到模板取到的data中去

return [apiVersion,datadictCopy]
分离变量文件和关键字文件是rf的规定,也是个好的编码习惯,以后vars.py中还要扩展其他更多更多的变量,当然common.py中也不可避免增加一些rf不擅长但python擅长处理的关键字。

3)大致长这样的mobile_post关键字:
最后,用一个rf的关键字,把一些关键数据组一组,该签名的签名,该登录的登录,该返回的返回:

5-2.png

再回到第1张图,待测接口comment.add,目标待传参数in_data为{"articleid":"3215","content":"大盘啥时候能好起来我就给好评","targetid":"","commentid":"","uid":"101123"},用例传参{"articleid":"3215","uid":"101123"},其他参数在模板中已默认,实际传参如目标待传。
 
4)结构:
 vars.py及common.py放同一级目录,以如下方式导入含有mobile_post的resource文件中

5-3导入结构.png

以上,仅提供思路。有些同学的接口入参及调用都很简单,3行内可以搞定一个接口,也可不必做得这么麻烦。在工程化的道路上,只有实践出来的路才是最好的路。

有更好的思路欢迎分享在评论~
 

使用robotframework做接口测试4——搞定接口签名及密码加密

RF教程雪霁 发表了文章 • 7 个评论 • 2437 次浏览 • 2017-03-11 15:29 • 来自相关话题

接口签名是我做接口测试撞到的第一块石头,刚到新公司,本来想默默憋出来一个大招,然后碰到了签名接口,直接给跪了。于是只好找开发哥哥帮忙,把签名算法的java文件拿到,一行行对着用python实现了一遍。大致的心路历程就是这样了,签名其实没什么好讲的,每个公司实现都不一样,java代码转成python代码也要点时间,传参类型和格式一定要对,调试的时候有人帮忙会快很多。

写这篇文章的目的之一,是粗略介绍一下自定义关键字的写法。另一目的是给有接口签名的小伙伴提供一些思路,不至于被一个老是变的字段吓到不敢前行。

有些小伙伴可能对签名什么的没有概念,那稍微解释一下。签名主要的作用是保证接口传值的完整性,一致性和安全性,一般会将时间戳及重要字段做成一个签名,作为一个参数传入,服务端收到请求后,首先对签名字段做校验,校验通过才做请求处理。在安全要求比较高一些的公司,比如金融行业,就会使用接口数字签名。

由于我们不是设计签名的,而只是翻译开发代码,就不考虑诸多细节了。假设签名签的字段为时间戳timestamp,重点字段:data1,data2,设备id:imei,签名的key为一个客户端和服务端约定的一个常量,如’abcd’。

算法过程如下:
对约定key值进行md5处理将规定字段拼接成一个长字符串,拼接时用&符号做为连接,拼接前把字符格式都转成了字符串将第二步得到的字符串进行md5处理
 以下是胡七八诌的python代码,可运行:#!/usr/bin/env python
# -*- coding: utf-8 -*-
import sys
reload(sys)
sys.setdefaultencoding('utf-8')
import hashlib
import json

class md5Enc(object):
def get_sign(self,data1,data2,imei="",t=""):
'''
Examples:
${sign} | Get Sign | api.name | ${userinfo} | 357070058113616 | ${t_now}
'''
#key string
key="abcd"
#第一步,key md5
keyMd5 = hashlib.md5()
keyMd5.update(key)
keyMd5= keyMd5.hexdigest()
data2Str = json.dumps(data2)
#第二步拼接签名
signBefore = data1 + "&" + data2Str + "&" + imei + "&" +\
t + "&" + keyMd5
#第三步sign md5
sign = hashlib.md5()
sign.update(signBefore)
sign = sign.hexdigest()

return sign

def get_pw_encrpt(self,pwBefore):
'''write your encrpt code here'''
print 'your encrpt code'

我的具体做法是把这个py文件命名为md5Enc.py(与类名一致)。py文件放在rf的项目文件里,如果和suite同级,以library的形式导入:





 
调用如下:





 
实际实践中,除了签名算法,还有密码加解密算法等,套路都差不多,有一些很简单的,只单纯一个md5的加密,应该用不到自定义关键字,稍微复杂一点的多层加密,什么AES啊,SHA256啊,base64啊,就考虑自己写写代码吧。
 
(最后吐个槽,我们公司密码加密算法太难写了。我偷了个懒,写了几个常用密码的字典。。。。比如{‘123456’:’XXXEEEWWSWDDDGGGSSS’,’111111’:’DDDWGREWHHSGDSFEWFDSRR’},嗯,就这样,还挺好用)
 
欢迎指出不足
 
  查看全部
接口签名是我做接口测试撞到的第一块石头,刚到新公司,本来想默默憋出来一个大招,然后碰到了签名接口,直接给跪了。于是只好找开发哥哥帮忙,把签名算法的java文件拿到,一行行对着用python实现了一遍。大致的心路历程就是这样了,签名其实没什么好讲的,每个公司实现都不一样,java代码转成python代码也要点时间,传参类型和格式一定要对,调试的时候有人帮忙会快很多。

写这篇文章的目的之一,是粗略介绍一下自定义关键字的写法。另一目的是给有接口签名的小伙伴提供一些思路,不至于被一个老是变的字段吓到不敢前行。

有些小伙伴可能对签名什么的没有概念,那稍微解释一下。签名主要的作用是保证接口传值的完整性,一致性和安全性,一般会将时间戳及重要字段做成一个签名,作为一个参数传入,服务端收到请求后,首先对签名字段做校验,校验通过才做请求处理。在安全要求比较高一些的公司,比如金融行业,就会使用接口数字签名。

由于我们不是设计签名的,而只是翻译开发代码,就不考虑诸多细节了。假设签名签的字段为时间戳timestamp,重点字段:data1,data2,设备id:imei,签名的key为一个客户端和服务端约定的一个常量,如’abcd’。

算法过程如下:
  1. 对约定key值进行md5处理
  2. 将规定字段拼接成一个长字符串,拼接时用&符号做为连接,拼接前把字符格式都转成了字符串
  3. 将第二步得到的字符串进行md5处理

 以下是胡七八诌的python代码,可运行:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import sys
reload(sys)
sys.setdefaultencoding('utf-8')
import hashlib
import json

class md5Enc(object):
def get_sign(self,data1,data2,imei="",t=""):
'''
Examples:
${sign} | Get Sign | api.name | ${userinfo} | 357070058113616 | ${t_now}
'''
#key string
key="abcd"
#第一步,key md5
keyMd5 = hashlib.md5()
keyMd5.update(key)
keyMd5= keyMd5.hexdigest()
data2Str = json.dumps(data2)
#第二步拼接签名
signBefore = data1 + "&" + data2Str + "&" + imei + "&" +\
t + "&" + keyMd5
#第三步sign md5
sign = hashlib.md5()
sign.update(signBefore)
sign = sign.hexdigest()

return sign

def get_pw_encrpt(self,pwBefore):
'''write your encrpt code here'''
print 'your encrpt code'

我的具体做法是把这个py文件命名为md5Enc.py(与类名一致)。py文件放在rf的项目文件里,如果和suite同级,以library的形式导入:

library1.png

 
调用如下:

自定义签名.png

 
实际实践中,除了签名算法,还有密码加解密算法等,套路都差不多,有一些很简单的,只单纯一个md5的加密,应该用不到自定义关键字,稍微复杂一点的多层加密,什么AES啊,SHA256啊,base64啊,就考虑自己写写代码吧。
 
(最后吐个槽,我们公司密码加密算法太难写了。我偷了个懒,写了几个常用密码的字典。。。。比如{‘123456’:’XXXEEEWWSWDDDGGGSSS’,’111111’:’DDDWGREWHHSGDSFEWFDSRR’},嗯,就这样,还挺好用)
 
欢迎指出不足
 
 

RobotFramework-Selenium2Library_V1.8中文版

RF教程zhangzhe0707 发表了文章 • 11 个评论 • 2196 次浏览 • 2017-02-28 12:11 • 来自相关话题

  对Selenium2Library 1.8版本中文版更新工作,因为公司项目上线的原因从年前一直拖到现在才完成.真是很不好意思.
  因为外语水平一般,通过Google的帮助和自己对Selenium2 API的了解才完成该文档翻译,如果有什么语义问题,欢迎大家扔砖指点。

更新内容
Selenium2Library1.8是将Selenium2 API版本更新到2.8,根据Selenium API更新内容,Library对关键字及元素定位方式做出了相应的更新.
 更新内容详见以下内容:

Locators定位方式
定位方式没有对通配符的支持新增 prefixes/strategies 的定位方式: link=, css=, tag=

新增关键字
Add Location Strategy Dismiss AlertGet Horizontal PositionGet Element SizeGet WebelementsGet Selenium SpeedGet Selenium TimeoutLog TitleLog LocationCapture Page Screensho
变更关键字
Choose File - 添加远端文件支持Click Button - 移出参数:dont_waitClick Element - 移出参数:dont_wait,coordinatesClick Image - 移出参数:dont_waitClick Link - 移出参数:dont_waitDouble Click Element - 移出参数:dont_wai, coordinates Go Back - 移出参数:dont_waitOpen Context Menu - 移出参数:offsePress Key - 移出参数:dont_waitargumentSelect All From List - 移出参数:waitSelect Radio Button - 移出参数:waitSubmit Form - 移出参数:dont_wait移出关键字Flex-related keywordsAdd Location StrategyCall Selenium APICapture Screenshot 替换为新关键字Capture Page Screenshot
  查看全部
  对Selenium2Library 1.8版本中文版更新工作,因为公司项目上线的原因从年前一直拖到现在才完成.真是很不好意思.
  因为外语水平一般,通过Google的帮助和自己对Selenium2 API的了解才完成该文档翻译,如果有什么语义问题,欢迎大家扔砖指点。

更新内容
Selenium2Library1.8是将Selenium2 API版本更新到2.8,根据Selenium API更新内容,Library对关键字及元素定位方式做出了相应的更新.
 更新内容详见以下内容:

Locators定位方式
  • 定位方式没有对通配符的支持
  • 新增 prefixes/strategies 的定位方式: link=, css=, tag=


新增关键字
  • Add Location Strategy 
  • Dismiss Alert
  • Get Horizontal Position
  • Get Element Size
  • Get Webelements
  • Get Selenium Speed
  • Get Selenium Timeout
  • Log Title
  • Log Location
  • Capture Page Screensho

变更关键字
  • Choose File - 添加远端文件支持
  • Click Button - 移出参数:dont_wait
  • Click Element - 移出参数:dont_wait,coordinates
  • Click Image - 移出参数:dont_wait
  • Click Link - 移出参数:dont_wait
  • Double Click Element - 移出参数:dont_wai, coordinates 
  • Go Back - 移出参数:dont_wait
  • Open Context Menu - 移出参数:offse
  • Press Key - 移出参数:dont_waitargument
  • Select All From List - 移出参数:wait
  • Select Radio Button - 移出参数:wait
  • Submit Form - 移出参数:dont_wait移出关键字Flex-related keywords
  • Add Location Strategy
  • Call Selenium API
  • Capture Screenshot 替换为新关键字Capture Page Screenshot

 

使用robotframework做接口测试三——保持登录状态

RF教程雪霁 发表了文章 • 10 个评论 • 7269 次浏览 • 2017-01-09 20:22 • 来自相关话题

  调用登录接口登录了,其他的接口怎么保持登录状态呢?
  首先来看一看,web端或者说客户端是怎么样用cookie/token等保持登录状态的。一般来说,cookie都会在登录接口由服务端返回,而且会是在header里面返回,并且,header里面有一个set-cookie这样的key,是的,就是这家伙,会把登录的cookie写到客户端的cookie缓存里,而后,当客户端要请求指向这个path的其它接口时,将此缓存的cookie塞到请求里面请求,服务端认得这个cookie,即认为后面的接口为已登录状态。
  当然,也不排除,有些变态的系统,cookie并不是由登录接口返回的。我碰到过一例,请求主页面时即返回set-cookie,然后客户端拿此cookie及用户名密码登录成功后,cookie激活。有点变态,不是常规实现,后来被重构了。还有些接口,直接把登录token啥的带在url里面,直接在url拼一拼就能完成鉴权。要具体问题具体分析,我接触的项目有限,只能讲讲比较常见的场景,给大家提供一些思路。
这是登录接口的返回headers截图:





 
  比较常见的情况下,关键字create session会创建session对象,下一个请求带上session别名,该session对象会自动完成请求在上下文传递过程中的 Cookie 处理,如下面的例子:





 
  另小伙伴们还可能有其他场景,如服务器间session共享,第二个请求要发往另一个host/域名,如某些app接口请求参数中需要带上cookie/token字段,部分SSO,这时候新请求可能需要创建另一个session,将cookie主动塞到session里面,f5可以看到create session关键字有个${cookies}参数,嗯,就是放到这里面,下图第11行脚本,注意是以键值对的方式传递的(抓包也看得出):





 
  第8行有个把set suite variable的操作,目的是在此suite下还有跨域名(如其它二级域名)的请求,也可以使用该登录cookie值,只要cookie未过期,只要服务器的session能识别。第8行也是为了重构做准备。
 
第一次重构:
  因为登录是一个很多接口都会依赖的动作,所以要把它抽取成关键字,个人建议是放在suite setup里面,这样做的好处是,省去了每个用例中都去调一次登录接口的时间。关键字抽取,会抽取图2的1-5行,图3中的1-8行做为一个关键字,将用户名密码设为入参,重构完,大概会变成:





 
  在这个suite中,是对banner功能点的接口测试集合,在suite setup里放了登录接口,用例一运行就先登录,名为newmanage的session保持了我的登录状态,其后的待测接口,都请求的同一个域名,因此使用alias为newmanage的get 和post请求,服务端认为已经登录,请求成功。

  还有前面说的另外一种情况,在登录时已经把cookie最核心的键值对取出来了,所以待测接口需要的话,新建个seesion把该cookie塞进去就行了,至于如何写会使脚本更精炼合理,建议按实际情况重构脚本。嗯,最后养成好习惯,suite结束时delete all sessions放在suite teardown下。

  之前也有看到过@懒猪 的接口脚本,可以直接把登录后的cookie整个的取出来,给下一个二级域名接口使用(而不是把cookie从header里取出分解出来再用),原理上是极其可行的,但在我们系统这种方法没有调试通过,也给大家推荐一下。
http://www.robotframework.net/?/article/88
 
  查看全部
  调用登录接口登录了,其他的接口怎么保持登录状态呢?
  首先来看一看,web端或者说客户端是怎么样用cookie/token等保持登录状态的。一般来说,cookie都会在登录接口由服务端返回,而且会是在header里面返回,并且,header里面有一个set-cookie这样的key,是的,就是这家伙,会把登录的cookie写到客户端的cookie缓存里,而后,当客户端要请求指向这个path的其它接口时,将此缓存的cookie塞到请求里面请求,服务端认得这个cookie,即认为后面的接口为已登录状态。
  当然,也不排除,有些变态的系统,cookie并不是由登录接口返回的。我碰到过一例,请求主页面时即返回set-cookie,然后客户端拿此cookie及用户名密码登录成功后,cookie激活。有点变态,不是常规实现,后来被重构了。还有些接口,直接把登录token啥的带在url里面,直接在url拼一拼就能完成鉴权。要具体问题具体分析,我接触的项目有限,只能讲讲比较常见的场景,给大家提供一些思路。
这是登录接口的返回headers截图:

登录cookie.png

 
  比较常见的情况下,关键字create session会创建session对象,下一个请求带上session别名,该session对象会自动完成请求在上下文传递过程中的 Cookie 处理,如下面的例子:

3-2第一个登录.png

 
  另小伙伴们还可能有其他场景,如服务器间session共享,第二个请求要发往另一个host/域名,如某些app接口请求参数中需要带上cookie/token字段,部分SSO,这时候新请求可能需要创建另一个session,将cookie主动塞到session里面,f5可以看到create session关键字有个${cookies}参数,嗯,就是放到这里面,下图第11行脚本,注意是以键值对的方式传递的(抓包也看得出):

3-2cookie.png

 
  第8行有个把set suite variable的操作,目的是在此suite下还有跨域名(如其它二级域名)的请求,也可以使用该登录cookie值,只要cookie未过期,只要服务器的session能识别。第8行也是为了重构做准备。
 
第一次重构:
  因为登录是一个很多接口都会依赖的动作,所以要把它抽取成关键字,个人建议是放在suite setup里面,这样做的好处是,省去了每个用例中都去调一次登录接口的时间。关键字抽取,会抽取图2的1-5行,图3中的1-8行做为一个关键字,将用户名密码设为入参,重构完,大概会变成:

3-4登录接口实现.png

 
  在这个suite中,是对banner功能点的接口测试集合,在suite setup里放了登录接口,用例一运行就先登录,名为newmanage的session保持了我的登录状态,其后的待测接口,都请求的同一个域名,因此使用alias为newmanage的get 和post请求,服务端认为已经登录,请求成功。

  还有前面说的另外一种情况,在登录时已经把cookie最核心的键值对取出来了,所以待测接口需要的话,新建个seesion把该cookie塞进去就行了,至于如何写会使脚本更精炼合理,建议按实际情况重构脚本。嗯,最后养成好习惯,suite结束时delete all sessions放在suite teardown下。

  之前也有看到过@懒猪 的接口脚本,可以直接把登录后的cookie整个的取出来,给下一个二级域名接口使用(而不是把cookie从header里取出分解出来再用),原理上是极其可行的,但在我们系统这种方法没有调试通过,也给大家推荐一下。
http://www.robotframework.net/?/article/88
 
 

使用robotframework做接口测试二——处理响应数据

RF教程雪霁 发表了文章 • 42 个评论 • 10598 次浏览 • 2017-01-06 16:37 • 来自相关话题

初使用RequestsLibrary做接口测试时,你会不会感到困惑,为什么会有${resp.content}, ${resp.status_code}这样的写法,这个status_code什么鬼,f5查的时候怎么没说明这个东西,为什么写Demo的人知道可以这么写,我少写个’_’可不可以,还有其它啥高端玩法是我不知道的,这玩意的使用说明到底保存在哪啊喂!
说到这个,我们先来了解一下,返回的${resp}是个什么类型的对象,在rf上用个巧妙的方法查看:






运行这段脚本,第4行的打印结果是:INFO : <class 'requests.models.Response'>
从结果可以看出${resp}是一个类对象,源码可在requests/models/Response查看,对象句点操作一般是取对象属性,顺藤摸瓜,找出该类的所有属性,第6行打印结果:
 ['__attrs__', '__bool__', '__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__getstate__', '__hash__', '__init__', '__iter__', '__module__', '__new__', '__nonzero__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__setstate__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_content', '_content_consumed', 'apparent_encoding', 'close', 'connection', 'content', 'cookies', 'elapsed', 'encoding', 'headers', 'history', 'is_permanent_redirect', 'is_redirect', 'iter_content', 'iter_lines', 'json', 'links', 'ok', 'raise_for_status', 'raw', 'reason', 'request', 'status_code', 'text', 'url']

粗体的是比较重要的,今后会被频繁使用的属性:

content: 响应body的内容,二进制编码,如果返回只有文本内容,和text差不多
cookies:响应回写的cookies,cookieJar类对象
headers: 响应头内容
json(): 响应body内容,json格式
status_code: 状态码
text: 响应body的内容,默认unicode编码

一、状态码
状态码什么的,百度上讲的肯定比我讲得清楚,我就不讲了。
另外,一般来说,系统内部会有一个自定义的响应码,与http的状态码不可混淆。
这里主要讲一下RequestsLibrary中对30X状态码的处理,默认情况下,RequestsLibrary的重定向是开着的,也就是说,如果请求返回的状态码为302,它会自动帮你访问重定向地址,并最终返回重定向地址的状态码。具体画风如何,请查看Demo:





二、处理一个简单的响应
响应body:
{
  "origin": "183.16.189.96"
}

不多说了,看图:第8行关键字需导入Collections库






三、处理多层级的响应body

这是一个一般复杂的响应body,多层级的json,实际中,你可能要取到某个nickName为“
test1”的数据并校验。
{
    "api": "api.name",
    "v": "1.0",
    "code": "10000",
    "error_msg": "success",
    "data": {
        "userlist": [{
            "uid": "94901",
            "nickName": "test1",
        }, {
            "uid": "1010640",
            "nickName": "test2",
        }, {
            "uid": "1012130",
            "nickName": "test3",
        }]
    }
}
还是希望大家有点python基础,这种json返回格式,一层层地来抽丝剥茧,{}为字典,用字典运算符,为list,用列表运算符,假设上面那个json是我的响应body。
取第一个nickName的值应该是这样:${resp.json()[‘data’][‘userlist’][0][‘nickName’]},log该变量,值应为:test1。用大白话解释这个表达式就是:把最外面的字典里的data的值里边的userlist的值的第一个字典元素取出来,再对这个字典里的nickName的值。好吧,我已经尽我最大能力翻译了。

另外还有人,可能想一次把所有列表中的nickName取了,也有个简单的办法:









这个用法有点炫酷,细说起来可以整成一个熟练使用rf+evaluate装逼指南系列。这是题外话了。对于初学者,还是1 要懂点python, 2 要懂rf和python之间的表达切换,rf里最好的调试语句是log。建议多写多log。 查看全部
初使用RequestsLibrary做接口测试时,你会不会感到困惑,为什么会有${resp.content}, ${resp.status_code}这样的写法,这个status_code什么鬼,f5查的时候怎么没说明这个东西,为什么写Demo的人知道可以这么写,我少写个’_’可不可以,还有其它啥高端玩法是我不知道的,这玩意的使用说明到底保存在哪啊喂!
说到这个,我们先来了解一下,返回的${resp}是个什么类型的对象,在rf上用个巧妙的方法查看:

2-1看resp类型.png


运行这段脚本,第4行的打印结果是:INFO : <class 'requests.models.Response'>
从结果可以看出${resp}是一个类对象,源码可在requests/models/Response查看,对象句点操作一般是取对象属性,顺藤摸瓜,找出该类的所有属性,第6行打印结果:
 ['__attrs__', '__bool__', '__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__getstate__', '__hash__', '__init__', '__iter__', '__module__', '__new__', '__nonzero__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__setstate__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_content', '_content_consumed', 'apparent_encoding', 'close', 'connection', 'content', 'cookies', 'elapsed', 'encoding', 'headers', 'history', 'is_permanent_redirect', 'is_redirect', 'iter_content', 'iter_lines', 'json', 'links', 'ok', 'raise_for_status', 'raw', 'reason', 'request', 'status_code', 'text', 'url']

粗体的是比较重要的,今后会被频繁使用的属性:

content: 响应body的内容,二进制编码,如果返回只有文本内容,和text差不多
cookies:响应回写的cookies,cookieJar类对象
headers: 响应头内容
json(): 响应body内容,json格式
status_code: 状态码
text: 响应body的内容,默认unicode编码

一、状态码
状态码什么的,百度上讲的肯定比我讲得清楚,我就不讲了。
另外,一般来说,系统内部会有一个自定义的响应码,与http的状态码不可混淆。
这里主要讲一下RequestsLibrary中对30X状态码的处理,默认情况下,RequestsLibrary的重定向是开着的,也就是说,如果请求返回的状态码为302,它会自动帮你访问重定向地址,并最终返回重定向地址的状态码。具体画风如何,请查看Demo:

2-3重定向.png

二、处理一个简单的响应
响应body:
{
  "origin": "183.16.189.96"
}

不多说了,看图:第8行关键字需导入Collections库

2-2普通响应.png


三、处理多层级的响应body

这是一个一般复杂的响应body,多层级的json,实际中,你可能要取到某个nickName为“
test1”的数据并校验。
{
    "api": "api.name",
    "v": "1.0",
    "code": "10000",
    "error_msg": "success",
    "data": {
        "userlist": [{
            "uid": "94901",
            "nickName": "test1",
        }, {
            "uid": "1010640",
            "nickName": "test2",
        }, {
            "uid": "1012130",
            "nickName": "test3",
        }]
    }
}
还是希望大家有点python基础,这种json返回格式,一层层地来抽丝剥茧,{}为字典,用字典运算符,为list,用列表运算符,假设上面那个json是我的响应body。
取第一个nickName的值应该是这样:${resp.json()[‘data’][‘userlist’][0][‘nickName’]},log该变量,值应为:test1。用大白话解释这个表达式就是:把最外面的字典里的data的值里边的userlist的值的第一个字典元素取出来,再对这个字典里的nickName的值。好吧,我已经尽我最大能力翻译了。

另外还有人,可能想一次把所有列表中的nickName取了,也有个简单的办法:

2-4处理多重json.png

2-5结果.png

这个用法有点炫酷,细说起来可以整成一个熟练使用rf+evaluate装逼指南系列。这是题外话了。对于初学者,还是1 要懂点python, 2 要懂rf和python之间的表达切换,rf里最好的调试语句是log。建议多写多log。

使用robotframework做接口测试之一——准备工作

RF教程雪霁 发表了文章 • 13 个评论 • 11708 次浏览 • 2017-01-06 15:06 • 来自相关话题

最近发现做接口测试的朋友越来越多了,打算写一个系列的rf+requests做接口测试(主要是Http接口)的文档,可以帮助新入门的同学对接口测试有个大概的了解,同时也是敦促自己做总结的一种手段。希望经验丰富的大神路过时,如发现我文档中的不足,提出中肯的批评及更好的解决思路。以期共同进步。
 
一、环境准备

1)默认已经安装robotframework
2)默认已经安装requests库
3)默认已经安装并成功导入RequestsLibrary
4)会用抓包工具,fiddler或Charles都可

用这个库做接口测试,希望用户本身对这个库有一定的了解,如果不了解,那么我们来叨一叨选择的理由。
1)Python的requests库号称是“HTTP for Humans”,它提供了非常方便且人性化的接口调用方法,上手快,功能强大且完美,甩同类库urllib2, httplib好几条街。国外网友的使用心得大多是,呵呵呵呵,用requests库十几行代码,把以前的几百行代码重构了。缺点是封装了太多层,不利于http底层原理的理解。中文版用户指南:http://docs.python-requests.org/zh_CN/latest/user/quickstart.html 
2)RequestsLibrary是基于requests模块做的RF库,其根基本身就强大,再加上git上有一些大神一直在对其进行持续地更新及维护,提供了很不错的官方Demo,从使用人数来说,也是完爆那些HTTPLibrary之流,意味着遇到问题得到解答的机会更大。Git地址:https://github.com/bulkan/robotframework-requests/
 
二、Http接口测试初窥
这一节要写一个get请求的例子,强烈推荐使用官方Demo入门,并且建议新老用户都熟悉Demo的每一个细节,对,是每一个细节。笔者当初多走了许多弯路,对这个细致的Demo相见恨晚,每次都温习demo而后知耻。。
第一个栗子:假如有个这样的get请求:https://api.github.com/users/bulkan,抓包





 
可以看出,这个接口请求中:
协议:  https
访问的host: api.github.com
root url(基础url): https://api.github.com
相对uri: /users/bulkan
method: get
传输参数: 无
该抓包其对应的测试用例如下:



 
 对应到用例,第一步创建一个到https://api.github.com的session,取个很容易认的别名github,第二步,使用get方法,访问别名为github的相对路径/users/bulkan。第3,4步断言返回数据。
对于前面两步,直接使用requests.get方法可以一步完成,为什么要强制拆成两步呢。可以大概揣测一下作者的意图:
1、使用别名,会使后面的请求写起来更顺手,用例也比较好看,大部分时候访问同一地址的请求,不需要重复创建session  
2、session的使用,可以实现跨请求保持一些cookie,这个功能才是session的重头戏。

Get request的好基友是post request,也是非常基础的必须掌握的一种请求方式,这个我就不写了。官方Demo几乎列出了所有可能出现的get 及post请求的例子,非常经典,实际项目中都能从里面找到原型。另外还有一些不常见的请求方式如head, put, delete等,也有例子。

三、如何开始你的接口测试第一步
首先,你得有项目组完善且规范的接口文档。好吧,大部分的中小公司的宝宝会说啥文档也没有。也可以通过抓包来开始做项目的接口demo,在无须外力的因素下迈出第一步,但是单凭抓包是抓不全的,所以最终实施前还是得搞来一份完整的接口文档,才能保证用例的覆盖。
单有接口文档也是不够的,还要学会如何抓包,抓包后知道如何解剖一个请求,重点关注请求的method, url, request header, request body, cookie, response header, response body等,还是那句话,办法永远比问题多,培养好的观察能力和解决问题能力无比重要。
 
 
接口测试的准备工作就写到这里,有好的建议请在评论里留言

参考文档:
Demo:https://github.com/bulkan/robotframework-requests/blob/master/tests/testcase.txt 
RequestsLibrary Git地址:https://github.com/bulkan/robotframework-requests/ 
Requests指南:http://docs.python-requests.org/zh_CN/latest/user/quickstart.html 查看全部
最近发现做接口测试的朋友越来越多了,打算写一个系列的rf+requests做接口测试(主要是Http接口)的文档,可以帮助新入门的同学对接口测试有个大概的了解,同时也是敦促自己做总结的一种手段。希望经验丰富的大神路过时,如发现我文档中的不足,提出中肯的批评及更好的解决思路。以期共同进步。
 
一、环境准备

1)默认已经安装robotframework
2)默认已经安装requests库
3)默认已经安装并成功导入RequestsLibrary
4)会用抓包工具,fiddler或Charles都可

用这个库做接口测试,希望用户本身对这个库有一定的了解,如果不了解,那么我们来叨一叨选择的理由。
1)Python的requests库号称是“HTTP for Humans”,它提供了非常方便且人性化的接口调用方法,上手快,功能强大且完美,甩同类库urllib2, httplib好几条街。国外网友的使用心得大多是,呵呵呵呵,用requests库十几行代码,把以前的几百行代码重构了。缺点是封装了太多层,不利于http底层原理的理解。中文版用户指南:http://docs.python-requests.org/zh_CN/latest/user/quickstart.html 
2)RequestsLibrary是基于requests模块做的RF库,其根基本身就强大,再加上git上有一些大神一直在对其进行持续地更新及维护,提供了很不错的官方Demo,从使用人数来说,也是完爆那些HTTPLibrary之流,意味着遇到问题得到解答的机会更大。Git地址:https://github.com/bulkan/robotframework-requests/
 
二、Http接口测试初窥
这一节要写一个get请求的例子,强烈推荐使用官方Demo入门,并且建议新老用户都熟悉Demo的每一个细节,对,是每一个细节。笔者当初多走了许多弯路,对这个细致的Demo相见恨晚,每次都温习demo而后知耻。。
第一个栗子:假如有个这样的get请求:https://api.github.com/users/bulkan,抓包

抓包截图.png

 
可以看出,这个接口请求中:
协议:  https
访问的host: api.github.com
root url(基础url): https://api.github.com
相对uri: /users/bulkan
method: get
传输参数: 无
该抓包其对应的测试用例如下:
图1.1_.png
 
 对应到用例,第一步创建一个到https://api.github.com的session,取个很容易认的别名github,第二步,使用get方法,访问别名为github的相对路径/users/bulkan。第3,4步断言返回数据。
对于前面两步,直接使用requests.get方法可以一步完成,为什么要强制拆成两步呢。可以大概揣测一下作者的意图:
1、使用别名,会使后面的请求写起来更顺手,用例也比较好看,大部分时候访问同一地址的请求,不需要重复创建session  
2、session的使用,可以实现跨请求保持一些cookie,这个功能才是session的重头戏。

Get request的好基友是post request,也是非常基础的必须掌握的一种请求方式,这个我就不写了。官方Demo几乎列出了所有可能出现的get 及post请求的例子,非常经典,实际项目中都能从里面找到原型。另外还有一些不常见的请求方式如head, put, delete等,也有例子。

三、如何开始你的接口测试第一步
首先,你得有项目组完善且规范的接口文档。好吧,大部分的中小公司的宝宝会说啥文档也没有。也可以通过抓包来开始做项目的接口demo,在无须外力的因素下迈出第一步,但是单凭抓包是抓不全的,所以最终实施前还是得搞来一份完整的接口文档,才能保证用例的覆盖。
单有接口文档也是不够的,还要学会如何抓包,抓包后知道如何解剖一个请求,重点关注请求的method, url, request header, request body, cookie, response header, response body等,还是那句话,办法永远比问题多,培养好的观察能力和解决问题能力无比重要。
 
 
接口测试的准备工作就写到这里,有好的建议请在评论里留言

参考文档:
Demo:https://github.com/bulkan/robotframework-requests/blob/master/tests/testcase.txt 
RequestsLibrary Git地址:https://github.com/bulkan/robotframework-requests/ 
Requests指南:http://docs.python-requests.org/zh_CN/latest/user/quickstart.html

RF新手常见问题总结--(基础篇)

RF教程Andy_xie 发表了文章 • 12 个评论 • 16451 次浏览 • 2016-12-30 10:53 • 来自相关话题

       学RF快一年了,经常碰到一些问题,有些同学也经常问到,这里总结一些,期望有人后续再补充,主要是响应群里--雪霁大神的号召,技术共享。废话少说,直接上干货了。

1. 经常有人问这个元素找不到,一般先排除这两个地方,再自己找找
A:是否等待了足够的时间让元素加载 (增加sleep xx, wait Until xxx)
B:  仔细查查,这个元素是否进入到另一个frame了 (select frame xxx)
上面两点都确定了还不行,那改变下xpath的方法

下面的方法掌握了,基本上没有找不到的。
C:xpath = //div[text()='web上显示的文本']  根据文本匹配
还有一文本前后可能有空格,特殊字符,可以用部分文本来匹配
D:xpath = //div[contains(text(),'部分文本')]
E:还有找父节点的方法: ../ 这个自己去看看,会有收获的。
 
2. 有同学问:如何判断这个元素disable,或者置灰了
用F12仔细看看元素灰了和没灰,disable和enable的区别,基本都能看到有的属性发生了改变, class的值多了或者少了checked, 或者disable等
一般这种我都用到 get element attribute关键字,如下获取class的属性
${class_value}  Get Element Attribute xpath=//div[@id=’123’]@class
你再判断 ${class_value}是否包含 disable,或者 check就可以得到其状态了
 
3. 有人说:我这个log怎么是乱码
 [ {‘dst': u'\u6cb3\u5317\u77012'}, {"xxx": "bbb"} ]
取出u'\u6cb3\u5317\u77012', 然后log就是中文了
 
4. 还有人问,我怎么没这个Get from Dictionary关键字,
其实是你没加载这些库,我建议:新手必须加载的库
BuiltIn             RF系统内部的,最基础的Run keyword xxx都在这里
String              字符串处理的库,文本处理必备
Collections        字典,列表的库,必备
Selenium2Library     web测试入门库
OperatingSystem     操作windows系统命令,处理文件时要用到
AutoItLibrary     鼠标、键盘操作windows控件用这个
 
 5. 还有人问我的数据库获取的怎么是乱码 ????? 一堆问号啥的
请在connect数据库时增加 charset=utf8 (我没弄过数据库的自动化,这个是看雪霁大神回答他人后记录下来的,还有其他可能的乱码,我不知道,请后续补充)
 
6. 还有人问,怎么设置全局变量
我们就谈谈RF变量的内部变量
${aaa}  Set Variable haha        这个${aaa}是普通变量,就本case能用
Set suite variable  ${aaa}     这个${aaa}就是测试suite变量
set global variable  ${aaa}   全局变量${aaa},在哪都能传
Set Test Variable   ${aaa}   (这个我还没用到过)
 
7. 有人说,我的日志输出想改个路径
在运行界面:Arguments右边输入框这样写  -l E:\Robot_log\smoke_test_log -r E:\Robot_log\smoke_test_report
-l 是log的路径参数
-r 是report的路径参数
如果还有其他执行脚本的需求,请命令行pybot -? 自己看看,都在这里
 
8. 还有人问:我的脚本assert,我还想继续执行,不想停下来
用这个几个,保证让你停不下来的节奏。。。
 Run Keyword And Return Status,
Run Keyword And Ignore Error
Run Keyword And Continue on Failure
 
9. 有新手经常问,我的浏览器怎么打不开
这种有提示:你的chromedriver没找到路径,我就不说了。
如果没这种提示的,基本就是你的ride,或者robotframework太旧了,还有就是你的浏览器版本太高了,
这种问题在道长经常在群里回答,我只是作为记录了,道长别找我要版权费哈。。。
 
10. 新手常见错误:If…  Else if… Else 怎么不行
这个确实是rf的坑,平时keyword都没区分大小写,但是这套IF语句一定要大写。
还有比较的时候,${aaa} == ${bbb}报语法错误,
因为你比较的时候没这样 ‘${aaa}’ == ‘${bbb}’  (请加上英文的单引号)
 
11. 还有,我导入库怎么是红色的
第一:请确定你是用pip在线安装的,其他下载文件安装很可能没安装好。
第二:请注意库命的大小写
第三,如果是你自己的自定义库红色,先运行下,看提示log,报错误在哪行,自己搞定语法错误
 
12. 这个弹出框怎么处理
一般处理弹窗先增加等待,容错处理
先用这个试试:Dismiss Alert
不行再用下面的
Choose Ok On Next Confirmation
Confirm action
顺便:get alert message --- 获取弹出窗的信息
13. 需要验证提示信息,(提示输入非法等等)用到鼠标悬停
Mouse Over xxx这样鼠标就挺在那了
马上去获取提示信息,get text  xxx
 
14. 日期控件怎么办,是否有关键字
RF没有日期控件的关键字,(我们是自己封装的)。
最简单的用js来执行 (我也不会js,找你们开发吧)
 
15. 这个下拉框我怎么选不上。
在浏览器F12下拉框
 
【正规的长这样 <option xxx> ,像下面这么用:
Select from List xpath=//xxx/xxx  灯姐
Selct from List by value  xxxx   萤草奶妈
 
非正规的下拉一般长这样: <div xxxx >,
你就用下面方式
Click Element xpath = //xxx/div[2]   ##先点下拉按钮
Click Element xpath=//xxx/xxx//div[text()='坦克程咬金']    ##再点下拉框中的元素

16. 那种2选1的按钮怎么做
官方称为Radio Button,在RF的selenium库中F5搜索 radio就有了
Select radio button  xxx   男

17. 多选按钮怎么做
Select checkbox

18. Click Button点不到元素
可以尝试下: click element
 
19. 没有这样的关键字咋办
没错,在你没有办法的时候,RF找来了他的经纪人“Python老宋”来帮忙。
Evaluate 后面接你的python代码就可以了。
 
20. 有人问:为什么我的IF … ELSE 跑到一行了,写的时候我是分开了的。
这个不用担心,RF就是这样自动的弄到一行了,不影响的。
 
21. 有人问:For循环怎么写?
就下面这样写,注意for前面有个冒号
:For  ${i}  IN RANGE  10
     Log  ${i} --- for循环内的语句在ride中前面要空一格
     Log  循环可以多行
 
22. 我写了IF语句,RF中如果让他执行多行关键字
对不起,rf的Run Keyword If语句后面不能像下面这样:
Run Keyword If   ‘xxx’ == ‘xxx’  语句1
                            语句2  //这样是不行的
                            语句3  //这样是不行的
下面这样是可以的
Run Keyword If   ‘xxx’ == ‘xxx’  语句1
Run Keyword If   ‘xxx’ == ‘xxx’  语句2 
Run Keyword If   ‘xxx’ == ‘xxx’  语句3
上面那样太麻烦,我有很多语句那咋办?
恭喜你,那只能自己封装关键字了,正好练习下封装技能!哈哈。。。
 
【特别说明】
  因为文档是在word中写了copy来的,其中编码的地方如果是引号,请全部用英文符合
 
以上我只是总结了群里的常见问题,不少问题都是群里的大神答案,拿来献丑了。
感谢我的RF老师--雪霁大神的指导和帮助! 祝雪霁女神永远的颜值担当!
再次感谢雪霁女神!!!
 
                                                             QQ: (1016109995追梦)
                                                             2016/12/29 中午 查看全部
       学RF快一年了,经常碰到一些问题,有些同学也经常问到,这里总结一些,期望有人后续再补充,主要是响应群里--雪霁大神的号召,技术共享。废话少说,直接上干货了。

1. 经常有人问这个元素找不到,一般先排除这两个地方,再自己找找
A:是否等待了足够的时间让元素加载 (增加sleep xx, wait Until xxx)
B:  仔细查查,这个元素是否进入到另一个frame了 (select frame xxx)
上面两点都确定了还不行,那改变下xpath的方法

下面的方法掌握了,基本上没有找不到的。
C:xpath = //div[text()='web上显示的文本']  根据文本匹配
还有一文本前后可能有空格,特殊字符,可以用部分文本来匹配
D:xpath = //div[contains(text(),'部分文本')]
E:还有找父节点的方法: ../ 这个自己去看看,会有收获的。
 
2. 有同学问:如何判断这个元素disable,或者置灰了
用F12仔细看看元素灰了和没灰,disable和enable的区别,基本都能看到有的属性发生了改变, class的值多了或者少了checked, 或者disable等
一般这种我都用到 get element attribute关键字,如下获取class的属性
${class_value}  Get Element Attribute xpath=//div[@id=’123’]@class
你再判断 ${class_value}是否包含 disable,或者 check就可以得到其状态了
 
3. 有人说:我这个log怎么是乱码
 [ {‘dst': u'\u6cb3\u5317\u77012'}, {"xxx": "bbb"} ]
取出u'\u6cb3\u5317\u77012', 然后log就是中文了
 
4. 还有人问,我怎么没这个Get from Dictionary关键字,
其实是你没加载这些库,我建议:新手必须加载的库
BuiltIn             RF系统内部的,最基础的Run keyword xxx都在这里
String              字符串处理的库,文本处理必备
Collections        字典,列表的库,必备
Selenium2Library     web测试入门库
OperatingSystem     操作windows系统命令,处理文件时要用到
AutoItLibrary     鼠标、键盘操作windows控件用这个
 
 5. 还有人问我的数据库获取的怎么是乱码 ????? 一堆问号啥的
请在connect数据库时增加 charset=utf8 (我没弄过数据库的自动化,这个是看雪霁大神回答他人后记录下来的,还有其他可能的乱码,我不知道,请后续补充)
 
6. 还有人问,怎么设置全局变量
我们就谈谈RF变量的内部变量
${aaa}  Set Variable haha        这个${aaa}是普通变量,就本case能用
Set suite variable  ${aaa}     这个${aaa}就是测试suite变量
set global variable  ${aaa}   全局变量${aaa},在哪都能传
Set Test Variable   ${aaa}   (这个我还没用到过)
 
7. 有人说,我的日志输出想改个路径
在运行界面:Arguments右边输入框这样写  -l E:\Robot_log\smoke_test_log -r E:\Robot_log\smoke_test_report
-l 是log的路径参数
-r 是report的路径参数
如果还有其他执行脚本的需求,请命令行pybot -? 自己看看,都在这里
 
8. 还有人问:我的脚本assert,我还想继续执行,不想停下来
用这个几个,保证让你停不下来的节奏。。。
 Run Keyword And Return Status,
Run Keyword And Ignore Error
Run Keyword And Continue on Failure
 
9. 有新手经常问,我的浏览器怎么打不开
这种有提示:你的chromedriver没找到路径,我就不说了。
如果没这种提示的,基本就是你的ride,或者robotframework太旧了,还有就是你的浏览器版本太高了,
这种问题在道长经常在群里回答,我只是作为记录了,道长别找我要版权费哈。。。
 
10. 新手常见错误:If…  Else if… Else 怎么不行
这个确实是rf的坑,平时keyword都没区分大小写,但是这套IF语句一定要大写。
还有比较的时候,${aaa} == ${bbb}报语法错误,
因为你比较的时候没这样 ‘${aaa}’ == ‘${bbb}’  (请加上英文的单引号)
 
11. 还有,我导入库怎么是红色的
第一:请确定你是用pip在线安装的,其他下载文件安装很可能没安装好。
第二:请注意库命的大小写
第三,如果是你自己的自定义库红色,先运行下,看提示log,报错误在哪行,自己搞定语法错误
 
12. 这个弹出框怎么处理
一般处理弹窗先增加等待,容错处理
先用这个试试:Dismiss Alert
不行再用下面的
Choose Ok On Next Confirmation
Confirm action
顺便:get alert message --- 获取弹出窗的信息
13. 需要验证提示信息,(提示输入非法等等)用到鼠标悬停
Mouse Over xxx这样鼠标就挺在那了
马上去获取提示信息,get text  xxx
 
14. 日期控件怎么办,是否有关键字
RF没有日期控件的关键字,(我们是自己封装的)。
最简单的用js来执行 (我也不会js,找你们开发吧)
 
15. 这个下拉框我怎么选不上。
在浏览器F12下拉框
 
【正规的长这样 <option xxx> ,像下面这么用:
Select from List xpath=//xxx/xxx  灯姐
Selct from List by value  xxxx   萤草奶妈
 
非正规的下拉一般长这样: <div xxxx >,
你就用下面方式
Click Element xpath = //xxx/div[2]   ##先点下拉按钮
Click Element xpath=//xxx/xxx//div[text()='坦克程咬金']    ##再点下拉框中的元素

16. 那种2选1的按钮怎么做
官方称为Radio Button,在RF的selenium库中F5搜索 radio就有了
Select radio button  xxx   男

17. 多选按钮怎么做
Select checkbox

18. Click Button点不到元素
可以尝试下: click element
 
19. 没有这样的关键字咋办
没错,在你没有办法的时候,RF找来了他的经纪人“Python老宋”来帮忙。
Evaluate 后面接你的python代码就可以了。
 
20. 有人问:为什么我的IF … ELSE 跑到一行了,写的时候我是分开了的。
这个不用担心,RF就是这样自动的弄到一行了,不影响的。
 
21. 有人问:For循环怎么写?
就下面这样写,注意for前面有个冒号
:For  ${i}  IN RANGE  10
     Log  ${i} --- for循环内的语句在ride中前面要空一格
     Log  循环可以多行
 
22. 我写了IF语句,RF中如果让他执行多行关键字
对不起,rf的Run Keyword If语句后面不能像下面这样:
Run Keyword If   ‘xxx’ == ‘xxx’  语句1
                            语句2  //这样是不行的
                            语句3  //这样是不行的
下面这样是可以的
Run Keyword If   ‘xxx’ == ‘xxx’  语句1
Run Keyword If   ‘xxx’ == ‘xxx’  语句2 
Run Keyword If   ‘xxx’ == ‘xxx’  语句3
上面那样太麻烦,我有很多语句那咋办?
恭喜你,那只能自己封装关键字了,正好练习下封装技能!哈哈。。。
 
【特别说明】
  因为文档是在word中写了copy来的,其中编码的地方如果是引号,请全部用英文符合
 
以上我只是总结了群里的常见问题,不少问题都是群里的大神答案,拿来献丑了。
感谢我的RF老师--雪霁大神的指导和帮助! 祝雪霁女神永远的颜值担当!
再次感谢雪霁女神!!!
 
                                                             QQ: (1016109995追梦)
                                                             2016/12/29 中午

RobotFramework-Selenium2Library中文版

RF教程zhangzhe0707 发表了文章 • 19 个评论 • 6538 次浏览 • 2015-04-30 11:11 • 来自相关话题

在公司工作不是太忙时和同事(daibing0527)一起对Robot Framework的当前Selenium2Library V1.6版本的英文关键字文档根据使用理解汉化。因为外语水平一般,也使用了Google翻译的帮助,如果有什么语义问题,欢迎大家扔砖指点。稍后有时候会继续把其它常用类库中文化。

2015-05-02:
修正关键字错误; 查看全部
在公司工作不是太忙时和同事(daibing0527)一起对Robot Framework的当前Selenium2Library V1.6版本的英文关键字文档根据使用理解汉化。因为外语水平一般,也使用了Google翻译的帮助,如果有什么语义问题,欢迎大家扔砖指点。稍后有时候会继续把其它常用类库中文化。

2015-05-02:
修正关键字错误;

RobotFramework使用cx_Oracle 报错“Dll load failed”解决办法

RF教程zhangzhe0707 发表了文章 • 1 个评论 • 2757 次浏览 • 2015-01-26 11:36 • 来自相关话题

RobotFramework在安装cx_Oracle后,如果直接连接Oracle数据库时,会出现“Dll load failed”错误。
因为Python在使用cx_Oracle类库访问oracle需要oci接口。当cx_Oracle找不到需要的oci的dll的时候就会报这个错误。

解决方法可以从oracle的客户端找3个dll文件拷贝到cx_Oracle的安装目录D:\Python25\Lib\site-packages

oraociei11.dll

oraocci11.dll

oci.dll

以上三个DLL下载地址:http://pan.baidu.com/s/1hqelwos 查看全部
RobotFramework在安装cx_Oracle后,如果直接连接Oracle数据库时,会出现“Dll load failed”错误。
因为Python在使用cx_Oracle类库访问oracle需要oci接口。当cx_Oracle找不到需要的oci的dll的时候就会报这个错误。

解决方法可以从oracle的客户端找3个dll文件拷贝到cx_Oracle的安装目录D:\Python25\Lib\site-packages

oraociei11.dll

oraocci11.dll

oci.dll

以上三个DLL下载地址:http://pan.baidu.com/s/1hqelwos