1、敏捷开发,接口一般数量很大,团队实现接口测试,版本控制。
2、功能太死板,有些接口完全无法实现(复杂的加密接口,签名接口等)
3、接口项目当中有多种不同协议的接口。
4、排错,定位接口问题不方便,结合抓包实现。
5、没有办法生成美观的报告。
6、多接口串联,数据库验证,日志监控。
7、有些公司做web自动化+接口自动化。
requests第三方库,主要用于发送http请求,做接口自动化。
#安装
pip install requests
| 请求 | |
|---|---|
| requests. get() | 发送get请求 |
| requests. post() | 发送post请求 |
| requests. delete() | 发送delete请求 |
| requests .put() | 发送put请求 |
| requests. request() | 最核心的方法 |
import requests
rep = requests.request();
| 响应 | |
|---|---|
| rep.text | 返回字符串的数据(文本格式) |
| rep.content | 返回字节格式的数据(图片、文件) |
| rep.json() | 返回字典格式的数据(json格式) |
| rep.status_code | 状态码 |
| rep.reason | 返回状态信息 |
| rep.cookies | 返回cookie信息 |
| rep.encoding | 返回编码格式 |
| rep.headers | 返回响应头信息 |
请求方式:get post put delete
请求参数类型: 键值对,JSON格式,文件格式
unittest、pytest管理用例框架:
前提是要安装pytest
pip install pytest
pytest默认规则:
1.py文件必须以test _ 开头或者 _ test结尾。
2类名必须以 Test 开头
3.测试用例必须以 test_ 开头
注意:
1、get请求通过params传递参数。
2、post请求通过json或者data传参。他们的区别是什么?
data
数据报文: dict字典类型,那么默认情况下请求头: application/x-www-form-urlencoded,
表示以form表单的方式传参,格式: a=1&b=2&c=3
数据报文: str类型,那么默认情况下: text/plain(如果是字典格式需要转换成str格式传参)
json
数据报文:不管是dict还是str类型,默认都是application/json ,格式: ({"a":1,"b".2)
data = {"tag": {"id": 134, "name": "广东人"}}
rep = requests.post(url=url, data=json.dumps(data))
json.dumps(data)序列化 把字典格式的数据转换成str格式.
json.loads(data)反序列化 把str格式转换成字典格式
总结:
data只能传递简单的只有键值对的dict或者是str格式。
json一般只能传dict格式(简单和嵌套都可以)
#3、文件传参files,且一定要open
data={
"media":open(r"E:\shu.png","rb")
}
rep = requests.post(url=url, files=data)
# 以下代码运行不起来,但是写法没错
import pytest
import requests
class TestSendRequest:
access_token=""
def test_get_token(self):
# 发送get请求
url = "https://api.weixin.qq.com/cgi-bin/token"
data = {
"grant_type": "client_credential",
"appid": "自己找素材",
"secret": "自己找素材"
}
rep = requests.get(url=url, params=data)
print(rep.json())
TestSendRequest.access_token = rep.json()["access_token"]
def test_edit_flag(self):
# 发送post请求(data和json只需要传一个,data和json的区别)
url = "https://api.weixin.qq.com/cgi-bin/token/tags/update?access_token=" + TestSendRequest.access_token + ""
data = {"tag": {"id": 134, "name": "广东人"}}
rep = requests.post(url=url, json=data)
print(rep.json())
if __name__ == '__main__':
#-vs 打印调试信息
pytest.main(['-vs'])
1、cookie鉴权: 网页的接口基本上都要做cookie鉴权。(不常用)
(给了token和请求头,但是请求还是fail,需要做cookie鉴权)
import re
import pytest
import requests
class TestSendRequest:
cks=""
#需要带请求头的接口以及需要cookie关 联的接口如何测试?
def test_start(self):
url = "http://47.107.116.139/phpwind/"
rep=requests.get(url=url)
print (rep.text)
#通过正则表达式获取鉴权码
TestSendRequest.csrf_token= re.search( 'name="csrf_token" value="(.*?)"', rep.text)[1]
print(TestSendRequest.csrf_token)
TestSendRequest.cks=rep.cookies
#请求需要带请求头的接口
def test_login(self) :
url = "http://47.107.116.139/phpwind/index.php?m=u&c=login&a=dorun"
data = {
"username" : "msxy",
"password" :"msxy",
"csrf_token": TestSendRequest.csrf_token,
"backurl": "http://47. 107.116.139/ phpwind/",
"invite": ""
}
headers = {
"Accept": "application/json,text/ javascript, / ; q=0.01",
"X一Requested-With" : "XMLHttpRequest"
}
rep = requests. post (url=url, data=data , headers=headers,cookies=TestSendRequest.cks )
print (rep.json() )
if __name__ == '__main__':
#-vs 打印调试信息
pytest.main(['-vs'])
2、通过session实现cookie鉴权(常用)
import re
import pytest
import requests
class TestSendRequest:
csrf_token=""
session = requests.session()
#需要带请求头的接口以及需要cookie关 联的接口如何测试?
def test_start(self):
url = "http://47.107.116.139/phpwind/"
rep=requests.get(url=url)
print (rep.text)
#通过正则表达式获取鉴权码
TestSendRequest.csrf_token= re.search( 'name="csrf_token" value="(.*?)"', rep.text)[1]
print(TestSendRequest.csrf_token
#请求需要带请求头的接口
def test_login(self) :
url = "http://47.107.116.139/phpwind/index.php?m=u&c=login&a=dorun"
data = {
"username" : "msxy",
"password" :"msxy",
"csrf_token": TestSendRequest.csrf_token,
"backurl": "http://47. 107.116.139/ phpwind/",
"invite": ""
}
headers = {
"Accept": "application/json,text/ javascript, / ; q=0.01",
"X一Requested-With" : "XMLHttpRequest"
}
rep = TestSendRequest.session.post (url=url, data=data , headers=headers)
print (rep.json() )
if __name__ == '__main__':
#-vs 打印调试信息
pytest.main(['-vs'])
rep=requests.request(请求方式,地址,参数…)
def test_get_token(self):
# 发送get请求
url = "https://api.weixin.qq.com/cgi-bin/token"
data = {
"grant_type": "client_credential",
"appid": "wx6b11b3efd1cdc290",
"secret": "106a9c6157c4db5f602991873819529d"
}
rep = requests.request("get",url=url, params=data)
print(rep.json())
TestSendRequest.access_token = rep.json()["access_token"]
1、它可以和所有的自动化测试工具selenium、requests、appium结合实现web自动化、接口自动化以及app自动化;
2、跳过用例、失败用例重跑;
3、结合allure生成美观的测试报告;
4、和Jenkins持续集成;
5、有很多的强大插件。
项目的在根目录下创建requirements.txt文件
注意:(#是我自己为了方便看代码的解释,复制请删除)
#pytest框架
pytest
#生产html测试报告
pytest-html
#多线程运行
pytest-xdist
#改变测试用例的执行顺序
pytest-ordering
#失败用例重跑
pytest-rerunfailures
#生产allure测试报告
allure-pytest
#在命令窗口使用 安装这个文件里面的插件
pip install -r requirements.txt
在根目录下创建python.ini文件
#提示这是pytest文件
[pytest]
#执行方法,-m "smoke" 只执行冒烟用例,要想执行其他用例 删除-m以及后面的
addopts = -vs -m "smoke"
#文件路径
testpaths = ./ui
#文件以test_开头
python_files = test_*.py
#类名以Test开头
python_classes = Test*
#用例以test_开头
python_functions = test_*
#对用例进行分组 在用例上@pytest.mark.smoke,就执行加了这样的用例
markers =
smoke:maoyan
若没有建立python.ini文件
在主程序中输出结果如下表达:
if __name__ == '__main__':
'''
v 输出更加详细的运行信息
-s 输出调试信息
-n 多线程运行
--reruns数字 失败用例重跑
--html='报告的路径'
'''
#写了pytest.ini
pytest.main()
# pytest.main(['-vs','-n=2'])
# pytest.main(['-vs','--reruns=2'])
# pytest.main(['-vs','--html=./report.html'])
setUp()/tearDown() 在每个用例之前/之后执行一次
setUp_class()/tearDown_class() 在每个类之前/之后执行一次
部分前置:
@pytest.fixture(scope=“作用域”,params=“数据驱动”,autouse=“自动执行”,ids=“自定义参数名”,name=“重命名”)
作用域: function(默认)、class、module、package/session
import requests
import re
import pytest
#部分前置
@pytest.fixture(scope="function")
def conn_database():
print("连接数据库")
#可以通过yield唤醒teardown的功能,就是返回,yield和return都有返回数据的意思
#但是yield返回多次及多个数据,return只返回一次且return后面的代码不执行
yield
print("关闭数据库")```
class Test:
def test_edit_flag(self,conn_database):
url=''
data={"tag":{"id":134,"name":"小李"}}
rep=Test.session.request('post',url,json=data
一般情况下:
@pytest.fixture()和conftest.py文件一起使用
conftest.py文件
1.conftest.py:文件是单独存放**@pytest.fixture()**的方法,可以实现多个py文件共享前置配置
2.conftest.py:不需要导入直接使用,可以直接使用
3.conftest.py:可以有多个,也可以有多个不同层级
import pytest
@pytest.fixture(scope="function")
def conn_database():
print("连接数据库")
yield
print("关闭数据库")
1、创建 common 文件夹,创建 yaml_util.py 文件
import os
import yaml
class YamlUtil:
#读取extract.yml文件
def read_extract_yaml(self,key):
with open(os.getcwd()+"./extract.yml",mode="r",encoding="utf-8") as f:
value=yaml.load(stream=f,Loader=yaml.FullLoader)
return value[key]
#写入extract.yml文件
def read_extract_yaml(self,data):
with open(os.getcwd()+"./extract.yml",mode="w",encoding="utf-8") as f:
yaml.dump(data=data,stream=f,allow_unicode=True)
#清除extract.yml文件
def clearn_extract_yaml(self):
with open(os.getcwd()+"./extract.yml",mode="w",encoding="utf-8") as f:
f.truncate()
2、创建extract.yml文件
3、创建conftest.py文件
import pytest
from common.yaml_util import YamlUtil
#autouse 自动执行,无需调用
#scope 作用域(session)
@pytest.fixture(scope="session",autouse=True)
def clearn_Yaml():
YamlUtil().clearn_extract_yaml()
# result ==>{"errcode": 0,"message":"数据返回成功"}
result = rep.json()
# 第一种
assert result['errcode'] == 0
#第二种
assert 'errcode' in rep.json()
#比较多个或者用and
assert 'errcode' in rep.json()
assert 'message' in rep.json()
assert 'errcode' in rep.json() and 1==1
https://github.com/allure-framework/allure2/releases
下载 .zip 的包,放到没有中文的路径下,然后把E:\allure-2.13.7\bin配置到环境变量的path里面哦
(1)在temp目录下生成临时的json文件的报告,在pytest.ini文件下写 - -alluredir ./temp
在当前目录下创建temp目录
[pytest]
#执行方法
addopts = -vs --alluredir ./temp
#文件路径
testpaths = ./ui
#文件以test_开头
python_files = test_*.py
#类名以Test开头
python_classes = Test*
#用例以test_开头
python_functions = test_*
(2)通过临时的json文件生成allure报告(在reports目录下),在all.py文件写
os.system(“allure generate temp -o reports --clean”)
在当前目录下创建 reports目录
import pytest
if __name__ == '__main__':
pytest.main()
os.system("allure generate temp -o reports --clean")
很好奇,就使用rubyonrails自动化单元测试而言,你们正在做什么?您是否创建了一个脚本来在cron中运行rake作业并将结果邮寄给您?git中的预提交Hook?只是手动调用?我完全理解测试,但想知道在错误发生之前捕获错误的最佳实践是什么。让我们理所当然地认为测试本身是完美无缺的,并且可以正常工作。下一步是什么以确保他们在正确的时间将可能有害的结果传达给您? 最佳答案 不确定您到底想听什么,但是有几个级别的自动代码库控制:在处理某项功能时,您可以使用类似autotest的内容获得关于哪些有效,哪些无效的即时反馈。要确保您的提
关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。
我正在编写一个包含C扩展的gem。通常当我写一个gem时,我会遵循TDD的过程,我会写一个失败的规范,然后处理代码直到它通过,等等......在“ext/mygem/mygem.c”中我的C扩展和在gemspec的“扩展”中配置的有效extconf.rb,如何运行我的规范并仍然加载我的C扩展?当我更改C代码时,我需要采取哪些步骤来重新编译代码?这可能是个愚蠢的问题,但是从我的gem的开发源代码树中输入“bundleinstall”不会构建任何native扩展。当我手动运行rubyext/mygem/extconf.rb时,我确实得到了一个Makefile(在整个项目的根目录中),然后当
我有一个围绕一些对象的包装类,我想将这些对象用作散列中的键。包装对象和解包装对象应映射到相同的键。一个简单的例子是这样的:classAattr_reader:xdefinitialize(inner)@inner=innerenddefx;@inner.x;enddef==(other)@inner.x==other.xendenda=A.new(o)#oisjustanyobjectthatallowso.xb=A.new(o)h={a=>5}ph[a]#5ph[b]#nil,shouldbe5ph[o]#nil,shouldbe5我试过==、===、eq?并散列所有无济于事。
我有一些Ruby代码,如下所示:Something.createdo|x|x.foo=barend我想编写一个测试,它使用double代替block参数x,这样我就可以调用:x_double.should_receive(:foo).with("whatever").这可能吗? 最佳答案 specify'something'dox=doublex.should_receive(:foo=).with("whatever")Something.should_receive(:create).and_yield(x)#callthere
Sinatra新手;我正在运行一些rspec测试,但在日志中收到了一堆不需要的噪音。如何消除日志中过多的噪音?我仔细检查了环境是否设置为:test,这意味着记录器级别应设置为WARN而不是DEBUG。spec_helper:require"./app"require"sinatra"require"rspec"require"rack/test"require"database_cleaner"require"factory_girl"set:environment,:testFactoryGirl.definition_file_paths=%w{./factories./test/
我遵循MichaelHartl的“RubyonRails教程:学习Web开发”,并创建了检查用户名和电子邮件长度有效性的测试(名称最多50个字符,电子邮件最多255个字符)。test/helpers/application_helper_test.rb的内容是:require'test_helper'classApplicationHelperTest在运行bundleexecraketest时,所有测试都通过了,但我看到以下消息在最后被标记为错误:ERROR["test_full_title_helper",ApplicationHelperTest,1.820016791]test
我收到这个错误:RuntimeError(自动加载常量Apps时检测到循环依赖当我使用多线程时。下面是我的代码。为什么会这样?我尝试多线程的原因是因为我正在编写一个HTML抓取应用程序。对Nokogiri::HTML(open())的调用是一个同步阻塞调用,需要1秒才能返回,我有100,000多个页面要访问,所以我试图运行多个线程来解决这个问题。有更好的方法吗?classToolsController0)app.website=array.join(',')putsapp.websiteelseapp.website="NONE"endapp.saveapps=Apps.order("
我已经构建了一些serverspec代码来在多个主机上运行一组测试。问题是当任何测试失败时,测试会在当前主机停止。即使测试失败,我也希望它继续在所有主机上运行。Rakefile:namespace:specdotask:all=>hosts.map{|h|'spec:'+h.split('.')[0]}hosts.eachdo|host|begindesc"Runserverspecto#{host}"RSpec::Core::RakeTask.new(host)do|t|ENV['TARGET_HOST']=hostt.pattern="spec/cfengine3/*_spec.r
我在app/helpers/sessions_helper.rb中有一个帮助程序文件,其中包含一个方法my_preference,它返回当前登录用户的首选项。我想在集成测试中访问该方法。例如,这样我就可以在测试中使用getuser_path(my_preference)。在其他帖子中,我读到这可以通过在测试文件中包含requiresessions_helper来实现,但我仍然收到错误NameError:undefinedlocalvariableormethod'my_preference'.我做错了什么?require'test_helper'require'sessions_hel