如何使用Pytest进行自动化测试

为何须要自动化测试



自动化测试有不少优势,但这里有3个主要的点:css


  1. 可重用性:不须要老是编写新的脚本,除非必要,即便是新的操做系统版本也不须要编写脚本。python

  2. 可靠性:人容易出错,机器不太可能。当运行不能跳过的重复步骤/测试时,速度会更快。nginx

  3. 全天运行:您能够在任什么时候间或远程启动测试。夜间运行正在测试你的软件,即便是在你睡着的时候。web


成熟的、功能齐全的Python测试工具——pytest


目前有多种可用的测试框架和工具。这些框架的风格也各不相同,好比数据驱动、关键字驱动、混合、BDD等等。您能够选择最适合您的要求。shell


Python和pytest在这场竞争中占据了巨大的份额。Python及其相关工具之因此被大量使用,多是由于与其余语言相比,没有或不多编程经验的人更能负担得起它们。django


pytest框架使得编写小型测试变得很容易,可是能够扩展到支持应用程序和库的复杂功能测试。编程


Pytest的一些主要特性:设计模式


  • 自动发现测试模块和功能api

  • 有效的CLI来更好地控制您想要运行或跳过的内容浏览器

  • 大型第三方插件生态系统

  • 固定装置-不一样的类型,不一样的范围

  • 与传统的单元测试框架一块儿工做


自动和可配置的测试发现


在默认状况下,pytest指望在名称以test_开头或以_test.py结尾的python模块中找到测试。在默认状况下,它指望测试函数名以test_ 开头。可是,能够经过在pytest的一个配置文件中添加您本身的配置来修改这个测试发现协议。


# content of pytest.ini# Example 1: have pytest look for "check" instead of "test"# can also be defined in tox.ini or setup.cfg file, although the section# name in setup.cfg files should be "tool:pytest"[pytest]python_files = check_*.pypython_classes = Checkpython_functions = *_check


让咱们看一下很是基本的测试函数。


class CheckClass(object): def one_check(self): x = "this" assert 'h' in x
def two_check(self): x = "hello" assert hasattr(x, 'check')


你注意到什么了吗?没有花哨的assertEqual或assertDictEqual等,只是简单明了的断言。对于比较两个对象的简单操做,不须要导入这些断言函数。assert是python已经提供的功能,所以无需从新发明。😊


固定装置会起做用的


查看测试功能,测试钱包软件的基本操做,好比,


// test_wallet.pyfrom wallet import Walletdef test_default_initial_amount(): wallet = Wallet() assert wallet.balance == 0 wallet.close()def test_setting_initial_amount(): wallet = Wallet(initial_amount=100) assert wallet.balance == 100 wallet.close()def test_wallet_add_cash(): wallet = Wallet(initial_amount=10) wallet.add_cash(amount=90) assert wallet.balance == 100 wallet.close()def test_wallet_spend_cash(): wallet = Wallet(initial_amount=20) wallet.spend_cash(amount=10) assert wallet.balance == 10 wallet.close()


嗯,有意思!你注意到了吗,不少样板文件。另外一件值得注意的事情是,测试除了测试功能以外还作了一些其余的事情,例如实例化钱包并关闭它——Wallet .close()


如今让咱们看看如何使用pytest fixture去除样板


import pytestfrom _pytest.fixtures import SubRequestfrom wallet import Wallet#==================== fixtures@pytest.fixturedef wallet(request: SubRequest): param = getattr(request, ‘param’, None) if param: prepared_wallet = Wallet(initial_amount=param[0]) else: prepared_wallet = Wallet() yield prepared_wallet prepared_wallet.close()#==================== testsdef test_default_initial_amount(wallet): assert wallet.balance == 0@pytest.mark.parametrize(‘wallet’, [(100,)], indirect=True)def test_setting_initial_amount(wallet): assert wallet.balance == 100@pytest.mark.parametrize(‘wallet’, [(10,)], indirect=True)def test_wallet_add_cash(wallet): wallet.add_cash(amount=90) assert wallet.balance == 100@pytest.mark.parametrize(‘wallet’, [(20,)], indirect=True)def test_wallet_spend_cash(wallet): wallet.spend_cash(amount=10) assert wallet.balance == 10


整洁!不是吗。测试函数很是微妙,只作它们想作的事情。夹具钱包负责设置和拆卸、实例化和关闭钱包。它不只有助于编写可重用的代码,还增长了数据分离的本质。若是仔细看,钱包数量是一块测试逻辑以外提供的测试数据,而不是硬编码在测试函数内部。


@pytest.mark.parametrize(‘wallet’, [(10,)], indirect=True)


在更可控的环境中,您能够在存储库中有一个测试数据文件,例如test-data.ini,以及读取该文件的包装器,而且您的测试函数能够调用包装器的另外一个接口来读取测试数据。


可是,建议将您的fixture做为conftest.py文件的一部分。这是pytest中的一个特殊文件,它容许测试发现全局fixture。


可是,有一个针对许多不一样数据集执行的测试用例!


不用担忧,pytest有一个很酷的特性来参数化您的fixture。让咱们用一个例子来看看它。


假设您的产品公开CLI接口以在本地管理它。此外,您的产品在启动时设置了许多默认参数,您须要验证全部这些参数的默认值。


咱们能够考虑为每一个设置编写一个测试用例,可是使用pytest就容易得多了


@pytest.mark.parametrize(“setting_name, setting_value”, [(‘qdb_mem_usage’, ‘low’),(‘report_crashes’, ‘yes’),(‘stop_download_on_hang’, ‘no’),(‘stop_download_on_disconnect’, ‘no’),(‘reduce_connections_on_congestion’, ‘no’),(‘global.max_web_users’, ‘1024’),(‘global.max_downloads’, ‘5’),(‘use_kernel_congestion_detection’, ‘no’),(‘log_type’, ‘normal’),(‘no_signature_check’, ‘no’),(‘disable_xmlrpc’, ‘no’),(‘disable_ntp’, ‘yes’),(‘ssl_mode’, ‘tls_1_2’),])def test_settings_defaults(self, setting_name, setting_value): assert product_shell.run_command(setting_name) == \ self.”The current value for \’{0}\’ is \’{1}\’.”.format(setting_name, setting_value), \ ‘The {} default should be {}’.format(preference_name, preference_value)


很酷,不是吗!,你只写了13个测试用例(每一个不一样setting_value),在将来若是你添加一个新的设置到你的产品,你须要作的就是,再添加一个tuple😌上面。


它是如何与selenium和API测试的UI测试集成的


嗯,你的产品能够有多种界面。CLI -就像咱们上面讨论的。相似地,GUI和API。在部署软件以前,对全部软件进行测试是很重要的。在多个组件相互依赖和耦合的企业软件中,某个部分的更改可能会影响其余部分。


记住,pytest只是一个促进“测试”的框架,而不是特定类型的测试。所以,您可使用selenium构建GUI测试,或者使用Python的请求库构建API测试,而后使用pytest运行它。


例如,在高层次上,这多是您的测试存储库结构。




正如您在上面看到的,这能够很好地分离组件。


  • apiobjects:为调用API端点建立包装器的好地方。您可使用BaseAPIObject和派生类来知足您的需求。

  • helper:编写您的helper方法

  • 库文件,它能够被不一样的组件使用,例如你的fixture在conftest, pageobjects等。

  • pageobjects: pageobjects设计模式可用于建立不一样GUI页面的类。咱们在站得住使用Webium,它是Python的一个页面对象模式实现库。

  • 套件:您能够在这里编写pylint代码验证套件,这将有助于您对代码质量有信心。

  • 测试:能够根据测试的风格对测试目录进行分类。它使管理和研究您的测试变得容易。


这只是供参考,存储库的结构和依赖关系能够按照您的须要进行布局。


我有足够的测试用例,想并行运行它们


您的测试套件中可能有大量的测试用例,而且有时您可能想并行地运行测试用例,以减小整体测试执行时间。


Pytest提供了一个很棒的并行运行测试的插件,名为Pytest -xdist,它用一些独特的执行模式扩展了Pytest。使用pip安装此插件


pip install pytest-xdist


让咱们经过一个示例来快速研究它。


我有一个自动化测试存储库CloudApp,用于使用selenium进行GUI测试。此外,它还随着新的测试用例不断增加,如今已经有了数百个测试。我想作的是并行运行它们,并减小测试执行时间。


在终端中,只需在项目根文件夹/ tests文件夹中键入pytest。这将执行全部测试。


pytest -s -v -n=2



并行运行测试的pytest-xdist


这还能够帮助您在多个浏览器上并行运行测试。


报告


Pytest内置支持建立结果文件,可由Jenkins、Bamboo或其余持续集成服务器读取,使用以下调用:


pytest test/file/path — junitxml=path


这能够生成很好的XML风格的输出,能够由许多CI系统解析器解释。

结论



Pytest的受欢迎程度逐年上升。此外,它还拥有普遍的社区支持,这让您能够访问不少扩展,好比pytest-django,它能够帮助您为Django web应用程序集成编写测试。记住,pytest支持运行unittest测试用例,因此若是您正在使用unittest, pytest是值得考虑的。😊


·END·
 

关注咱们

机器学习·数据分析


本文分享自微信公众号 - Python学会(gh_39aead19f756)。
若有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一块儿分享。

相关文章
相关标签/搜索