目录
pytest 是一个成熟的全功能 Python 测试工具,可以帮助您编写更好的程序。它与 Python 自带的 Unittest 测试框架类似,但 pytest 使用起来更简洁和高效,并且兼容 unittest 框架。

(1)什么是单元测试
单元测试是指在软件开发过程中,针对软件的最小单位(如函数、方法等)进行正确性的检查测试。
(2)常见的单元测试框架
Java:junit和testing
python:unittest和pytest
(3)单元测试框架主要做什么?
1. 测试发现:从多个文件中找到我们的测试用例
2. 测试执行:按照一定的顺序和规则执行并生成结果
3. 测试判断:通过断言判断预期结果和实际结果的差异
4. 测试报告:统计测试进度、耗时、通过率,生成测试报告
(1)什么是自动化测试
自动化测试包括一切通过工具(程序)的方式来代替或辅助手工测试的行为。其主要手段是模拟手工测试,通过组织编写自动化脚本执行测试用例,解决测试工作量大的问题,自动化测试能有效的提高测试效率。
(2)自动化测试的作用
1. 提高测试效率,降低维护成本
2. 减少人工干预,提高测试准确性,增加代码的复用性
(3)二者的关系
单元测试是自动化测试的组成部分之一
1. pytest是一个非常成熟的python单元测试框架,比unittest更加灵活,容易上手
2. pytest可以和selenium、request、qppium结合实现web自动化、接口自动化、app自动化
3. pytest可以实现测试用例的跳过及rerun失败用例重试
4. pytest可以和allure生成非常美观的测试报告
5. pytest可以和Jenkins持续集成
6. pytest有很多强大的插件
pytest-html (生成html格式的自动化测试报告)
pytest-xdist (测试用例分布式执行,多cpu分发)
pytest-ordering (用于改变测试用例的执行顺序)
pytest-rerunfailures (用例失败后重跑)
allure-pytest (用于生成美观的测试报告)
在这里我们可以一次性将这些插件一起导入项目中,具体操作如下:

输入pytest -version 即可查看是否导入成功,如果显示失败,可以查看一下位置是否出现错误

1. 模块名必须以test_开头或_test结尾
2. 测试类必须以Test开头,并且不能有init方法
3. 测试方法必须以test开头

(1)主函数模式
1. 运行所有:pytest.main()
if __name__ == '__main__':
pytest.main()
2. 指定模块:
if __name__ == '__main__':
pytest.main(['-vs','test_id.py'])
ps:我用的是mac系统,在写.py文件的路径时是这样写的,如果是win,注意一下文件路径即可。
3. 指定目录
if __name__ == '__main__':
# 测试interface_testcase 目录下的全部用例
pytest.main(['-vs','interface_testcase'])
if __name__ == '__main__':
# 测试interface_testcase 目录下的test_interface01.py 中的用例
pytest.main(['-vs','interface_testcase/test_interface01.py'])
(2)命令行模式
1. 运行所有:pytest
2. 指定模块:pytest test_goods.py
3. 指定目录:pytest testcase
pytest testcase/test_goods.py
pytest中的参数详解:
-s:表示输出调试信息,输出print信息
-v:显示更加详细的信息
-vs:两个参数可以同时使用
-n:支持多线程或者分布式运行
if __name__ == '__main__':
# 有两个线程来执行testcase 目录下的测试用例
pytest.main(['-vs','testcase','-n 2'])
--reruns=NUM:失败用例重跑,将这个模块多执行num次,最后返回结果
if __name__ == '__main__':
pytest.main(['-vs','--reruns=2'])
-x:只要有一个用例失败,测试就会停止
-maxfail=2:如果有两个测试用例失败,测试停止
-k:根据测试用例的部分字符串指定测试用例
if __name__ == '__main__':
# 在testcase 目录下,带有case的测试用例全部被执行
pytest.main(['-vs','testcase','-k "case"'])
(3)通过读取pytest.ini配置文件运行
pytest.ini是pytest单元测试框架的核心配置文件
1. 位置:一般放在项目的根目录
2. 编码:必须是ANSI,可以使用notepad++修改编码格式
3. 作用:改变pytest默认的行为
4. 运行规则:不管是主函数的模式运行还是命令行模式运行,都会读取这个文件
pytest.ini配置文件的示例如下:

unittest:根据ASCII大小执行
pytest:默认按照用例先后顺序执行
可以通过@pytest.mark.run(order=)来指定执行顺序


if __name__ == '__main__':
# 只执行smoke
pytest.main(['-vs','-m "smoke"'])
if __name__ == '__main__':
# 执行smoke或者usermanage
pytest.main(['-vs','-m "smoke or usermanage"'])
(1)无条件跳过
@pytest.mark.skip(reason="")
(2)有条件跳过
class TestStudent:
age = 20;
@pytest.mark.skipif(age>18, reason="age is over 18")
def test_01(self):
print('age is 20')
(1)setup/teardown,setup_class/teardown_class
为什么需要这些功能?
比如:web自动化执行用例之前都需要打开浏览器,在用例执行完毕后都要关闭浏览器。如果每一次都重新写打开、关闭浏览器的代码会造成代码冗余。
setup/teardown 示例如下:这种方式的前后置会在每一个测试用例前后都执行一次
class TestA:
def setup(self):
print("\n open the client")
def test_01(self):
print('this is a test')
def teardown(self):
print("\n close the client")
if __name__ == '__main__':
pytest.main()
setup_class/teardown_class 示例如下:这种方式的前后置会在每个类前后执行一次
class TestA:
def setup_class(self):
print("\n open the client")
def test_01(self):
print('this is a test')
def teardown_class(self):
print("\n close the client")
if __name__ == '__main__':
pytest.main()
(2)使用@pytest.fixture装饰器实现部分用例的前后置
@pytest.fixture装饰器的几个参数:
scope:表示被装饰器标记的方法的作用域(function默认,class,module,package,session)
params:参数化(支持list[],tuple(),[(),()],([],[]))
autouse=True:自动执行,默认是false
ids:当使用params参数时,给每一个参数设置一个变量名
name:标记方法的别名
只实现前置的示例:
@pytest.fixture(scope="function")
# 这个my_fixture()只能被当前.py文件中的函数使用
def my_fixture():
print("实现前置")
class TestA:
def test_01(self,my_fixture):
print('this is a test')
if __name__ == '__main__':
pytest.main()
既有前置又有后置的示例:
@pytest.fixture(scope="function")
def my_fixture():
print("实现前置")
yield
print("实现后置")
class TestA:
def test_01(self,my_fixture):
print('this is a test')
if __name__ == '__main__':
pytest.main()
(3)通过conftest.py和@pytest.fixture()结合实现全局前置
1. conftest.py文件是一个单独存放的夹具配置文件,名称不能更改
2. 可以在不同的.py文件中使用同一个my_fixture函数
3. conftest.py需要和运行的测试用例放在同一级目录下
接口自动化测试小示例:(本次使用的接口说B站上的软件测试课程网站)
class TestApi:
def test_02(self):
# 如果想用我这个示例来做实验的话,需要将这个网页先打开
# https://www.bilibili.com/video/BV1Wf4y147en?p=9&spm_id_from=pageDriver
url = 'https://www.bilibili.com/video/BV1Wf4y147en'
params = {
"p" :"9",
"spm_id_from":"pageDriver"
}
# 这里要导入一个requests库
res = requests.get(url,params=params)
print(res.text)
if __name__ == '__main__':
pytest.main()
将上面的测试用例转换成读取YAML文件形式:
先写一个YAML文件,如下:
注意!冒号的后面一定要有空格!!!这是yaml文件的格式

然后编译读取YAML文件的工具类
class YamlUtil:
def __init__(self,yaml_file):
self.yaml_file = yaml_file
def read_yaml(self):
with open(self.yaml_file,encoding='utf-8') as f:
# 反序列化
value = yaml.load(f,Loader=yaml.FullLoader)
print(value)
return value
最后进行测试
class TestApi:
@pytest.mark.parametrize('args', YamlUtil('testcase/test_api.yaml').read_yaml())
def test_01_baili(self, args):
print(args)
url = args['request']['url']
params = args['request']['params']
res = requests.get(url, params=params)
print(res.text)
if __name__ == '__main__':
pytest.main()
感谢每一个认真阅读我文章的人!!!
如果下面这些资料用得到的话可以直接拿走:
1、自学开发或者测试必备的完整项目源码与环境
2、测试工作中所有模板(测试计划、测试用例、测试报告等)
3、软件测试经典面试题
4、Python/Java自动化测试实战.pdf
5、Jmeter/postman接口测试全套视频获取
6、Python学习路线图
重点:配套学习资料和视频教学
那么在这里我也精心准备了上述大纲的详细资料包含:电子书,简历模板,各种工作模板,面试宝典,自学项目等。需要的朋友和我在评论区互动交流吧!
很好奇,就使用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
我已经构建了一些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
只是想确保我理解了事情。据我目前收集到的信息,Cucumber只是一个“包装器”,或者是一种通过将事物分类为功能和步骤来组织测试的好方法,其中实际的单元测试处于步骤阶段。它允许您根据事物的工作方式组织您的测试。对吗? 最佳答案 有点。它是一种组织测试的方式,但不仅如此。它的行为就像最初的Rails集成测试一样,但更易于使用。这里最大的好处是您的session在整个Scenario中保持透明。关于Cucumber的另一件事是您(应该)从使用您的代码的浏览器或客户端的角度进行测试。如果您愿意,您可以使用步骤来构建对象和设置状态,但通常您