使用Pytest进行自动化测试

本文的翻译是专门为Python QA工程师课程的学生准备的。




我们生活在一个软件正迅速推向市场的时代。 因此,开发过程变得非常紧张。 较高的软件实施速度和快速交付看起来是业务模型的重要组成部分,但是这里出现了有关如何交付质量合适的软件的问题。

为什么我们需要自动化测试


自动化测试有很多优点,这是三个主要优点:
重用:即使有新版本的操作系统,也不必每次都编写新的脚本,除非迫切需要。
可靠性:人们容易犯错误,而汽车则使错误发生的可能性降低。 当执行需要连续执行的重复步骤/测试时,它们的工作速度更快。
工作24/7:您可以在一天中的任何时间(甚至是远程)开始测试。 如果您从晚上开始测试,即使您在睡觉时也可以运行。

用Python开发的全功能pytest测试工具


当前,有许多测试框架和工具。 有不同类型的框架,例如,数据驱动,关键字驱动,混合,BDD等。 您可以选择最适合您的要求的一种。

我必须说,Python和pytest在这件事上占据着巨大的位置。 Python及其相关工具得到了广泛的使用,可能是因为与其他语言相比,几乎没有编程经验的人更容易使用它们。

pytest框架pytest编写小型测试pytest容易,但它也可以扩展以支持应用程序和库的复杂功能测试。

pytest一些关键功能:

  • 自动检测测试模块和功能;
  • 有效的CLI可改善对您要运行或跳过的内容的控制;
  • 大型第三方插件生态系统;
  • 夹具-不同类型,不同应用;
  • 使用传统的单元测试框架。

自动和可配置的测试检测


默认情况下, pytest期望在名称以test_test_结束的Python模块中查找测试。 另外,默认情况下,它期望测试函数的名称以前缀test_ 。 但是,可以通过将您自己的配置添加到pytest配置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_*.py python_classes = Check python_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') 

你有没有注意到? 没有assertEqualassertDictEqual ,只有可访问且可理解的assert 。 无需导入这些函数即可简单地比较两个对象。 断言是Python已经拥有的东西,不需要重新发明轮子。

模板代码? 不用担心,夹具会抢救!


查看测试电子钱包程序中基本操作的测试函数:

 // test_wallet.py from wallet import Wallet def 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并使用wallet.close()将其关闭。

现在让我们看一下如何使用pytest pytest摆脱样板代码。

 import pytest from _pytest.fixtures import SubRequest from wallet import Wallet #==================== fixtures @pytest.fixture def 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() #==================== tests def 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 

很好,不是吗? 现在,测试功能非常紧凑,并且可以完全执行它们应该执行的操作。 使用wallet配置,安装和关闭电子wallet 。 固定装置不仅有助于编写可重用的代码,而且还增加了数据共享的概念。 如果仔细观察, wallet的金额就是测试逻辑外部提供的测试数据的一部分,而不是固定在函数内部。

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

在更受控制的环境中,您可能具有一个包含测试数据的文件,例如可以读取该文件的存储库或外壳中的test-data.ini ,而您的测试功能可以调用各种外壳以读取测试数据。

但是,建议将所有灯具放在一个特殊的conftest.py文件中。 这是pytest中的一个特殊文件,允许测试检测全局夹具。

但是我有一些要在不同数据集上运行的测试用例!


别担心, pytest具有一个很酷的功能来参数化您的灯具。 让我们来看一个例子。

假设您的产品具有本地管理的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 ),并且将来,如果您向产品中添加新参数,那么您要做的就是添加另一个元组。

pytest如何与Selenium和API测试的用户界面测试集成?


好吧,您的产品可能有多个接口。 CLI-如上所述。 类似于GUI和API。 在部署软件产品之前,对所有产品进行测试非常重要。 在企业软件中,几个组件相互连接并且相互依赖,一个部分的更改会影响所有其他部分。

请记住, pytest只是用于简单测试的框架,而不是特定类型的测试。 也就是说,您可以使用Selenium为GUI创建测试,或者使用Python的requests库为API创建测试,然后使用pytest运行它们。

例如,在较高级别上,这可能是对存储库结构的检查。



如您在上图中所看到的,这为分离组件提供了一个很好的机会:

apiobjects :创建用于调用API端点的包装器的好地方。 您可能拥有一个BaseAPIObject和一个满足您要求的派生类。

helpers :您可以在这里添加您的helper方法。

lib :可以由各种组件使用的库文件,例如, conftestconftestpageobjects等。

pageobjectsPageObjects体系结构PageObjects可用于为各种GUI页面创建类。 我们使用Webium ,它是Python页面对象模板的实现库。

套件 :您可以编写自己的一组pylint检查代码,它们将帮助您对代码质量更有信心。

测试 :您可以根据自己的喜好对测试进行分类。 这将使管理和检查测试变得容易。

我带来它只是为了参考,可以根据您的个人需求来组织存储库的结构和依赖项。

我有很多测试用例,我希望它们可以并行运行


您的集合中可以有许多测试用例,碰巧您需要并行运行它们并减少总体测试执行时间。

Pytest提供了一个很棒的并行测试运行插件pytest-xdist ,它为基本pytest添加了几种独特的执行模式。 使用pip安装此插件。

 pip install pytest-xdist 

让我们来看一个例子。

我有一个用于Selenium GUI测试的CloudApp自动化测试存储库。 此外,它还在不断发展和更新新的测试,现在有数百个测试。 我想做的是并行运行它们,并减少总体测试执行时间。

在终端中,只需在项目根文件夹/ test文件夹中键入pytest 。 这将允许您执行所有测试。

 pytest -s -v -n=2 



pytest-xdist将并行运行所有测试!

这样,您还可以并行运行多个浏览器。

报告书


Pytest内置支持创建测试结果文件的功能,可以使用Jenkins,Bamboo或其他持续集成服务器打开这些测试结果文件。 使用以下内容:

 pytest test/file/path — junitxml=path 

这将有助于生成可通过许多解析器打开的出色XML文件。

结论


Pytest的知名度每年都在增长。 此外,它还具有强大的社区支持,使您可以访问许多扩展,例如pytest-django ,这将帮助您在Django中编写针对Web应用程序的测试。 请记住,pytest支持unittest测试用例,因此,如果使用unittest ,则应该更详细地考虑pytest。

资料来源



仅此而已。 在课程中见!

Source: https://habr.com/ru/post/zh-CN480186/


All Articles