pytest:同一接口的不同实现的可重用测试

2024-05-21

想象一下我已经实现了一个名为的实用程序(可能是一个类)Bar在一个模块中foo,并为其编写了以下测试。

测试_foo.py:

from foo import Bar as Implementation
from pytest import mark

@mark.parametrize(<args>, <test data set 1>)
def test_one(<args>):
    <do something with Implementation and args>

@mark.parametrize(<args>, <test data set 2>)
def test_two(<args>):
    <do something else with Implementation and args>

<more such tests>

现在想象一下,将来我希望编写同一接口的不同实现。我希望这些实现能够重用为上述测试套件编写的测试:唯一需要更改的是

  1. 进口的Implementation
  2. <test data set 1>, <test data set 2> etc.

因此,我正在寻找一种以可重用的方式编写上述测试的方法,这将允许接口的新实现的作者能够通过将实现和测试数据注入其中来使用测试,而无需修改包含测试原始规范的文件。

在 pytest 中执行此操作的一个好的、惯用的方法是什么?

=================================================== =================

=================================================== =================

这是一个(不太漂亮但)有效的单元测试版本。

定义_测试.py:

# Single, reusable definition of tests for the interface. Authors of
# new implementations of the interface merely have to provide the test
# data, as class attributes of a class which inherits
# unittest.TestCase AND this class.
class TheTests():

    def test_foo(self):
        # Faking pytest.mark.parametrize by looping
        for args, in_, out in self.test_foo_data:
            self.assertEqual(self.Implementation(*args).foo(in_),
                             out)

    def test_bar(self):
        # Faking pytest.mark.parametrize by looping
        for args, in_, out in self.test_bar_data:
            self.assertEqual(self.Implementation(*args).bar(in_),
                             out)

v1.py:

# One implementation of the interface
class Implementation:

    def __init__(self, a,b):
        self.n = a+b

    def foo(self, n):
        return self.n + n

    def bar(self, n):
        return self.n - n

v1_测试.py:

# Test for one implementation of the interface
from v1 import Implementation
from define_tests import TheTests
from unittest import TestCase

# Hook into testing framework by inheriting unittest.TestCase and reuse
# the tests which *each and every* implementation of the interface must
# pass, by inheritance from define_tests.TheTests
class FooTests(TestCase, TheTests):

    Implementation = Implementation

    test_foo_data = (((1,2), 3,  6),
                     ((4,5), 6, 15))

    test_bar_data = (((1,2), 3,  0),
                     ((4,5), 6,  3))

任何人(甚至是库的客户端)编写此接口的另一个实现

  • 可以重用中定义的测试集define_tests.py
  • 将自己的测试数据注入到测试中
  • 不修改任何原始文件

这是一个很好的用例参数化测试夹具 https://docs.pytest.org/en/latest/fixture.html#fixture-parametrize.

您的代码可能如下所示:

from foo import Bar, Baz

@pytest.fixture(params=[Bar, Baz])
def Implementation(request):
    return request.param

def test_one(Implementation):
    assert Implementation().frobnicate()

这会有test_one运行两次:一次为 Implement=Bar,一次为 Implement=Baz。

请注意,由于实现只是一个固定装置,因此您可以更改其范围,或进行更多设置(也许实例化该类,也许以某种方式配置它)。

如果与pytest.mark.parametrize装饰器,pytest 将生成所有排列。例如,假设上面的代码和这里的代码:

@pytest.mark.parametrize('thing', [1, 2])
def test_two(Implementation, thing):
    assert Implementation(thing).foo == thing

test_two将运行四次,配置如下:

  • 实施=酒吧,事情=1
  • 实施=酒吧,事情=2
  • 实施=Baz,事物=1
  • 实施=Baz,事物=2
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

pytest:同一接口的不同实现的可重用测试 的相关文章

  • 如何让“conda”安装程序查找“PyPi”包

    我试图使用conda http conda pydata org docs using pkgs html managing packages包管理器来安装我的 Python 包 最近 我遇到了 Anaconda org 存储库中不存在我需
  • Flask-SocketIO redis 订阅

    我在用着https github com miguelgrinberg Flask SocketIO https github com miguelgrinberg Flask SocketIO实现 WebSocket 服务器 我需要从另一
  • 在函数内的 for 循环上使用 tqdm 来检查进度

    我正在使用 for 循环迭代目录树内的一大组文件 这样做时 我想通过控制台中的进度条来监视进度 因此 我决定使用 tqdm 来实现此目的 目前 我的代码如下所示 for dirPath subdirList fileList in tqdm
  • GUI 测试工具 PyUseCase 与 Dogtail 相比如何?

    GUI测试工具如何Py用例 http pypi python org pypi PyUseCase重命名为故事文本 http pypi python org pypi StoryText 相比于Dogtail http en wikiped
  • 如何替换Python字符串中的正确字母

    任务是 您的任务是纠正数字化文本中的错误 您只需处理以下错误 S 被误解为 5 O 被误解为 0 I 被误解为 1 我的代码 def correct string for i in string if 5 in string string
  • 使用管理员权限打开cmd(Windows 10)

    我有自己的 python 脚本来管理我的计算机上的 IP 地址 它主要在命令行 Windows 10 中执行netsh命令 您必须具有管理员权限 这是我自己的计算机 我是管理员 运行脚本时我已经使用管理员类型的用户 Adrian 登录 我无
  • 使用 Tkinter 打开网页

    因此 我的应用程序需要能够打开其中的单个网页 并且它必须来自互联网并且未保存 特别是我想使用 Tkinter GUI 工具包 因为它是我最熟悉的工具包 最重要的是 我希望能够在窗口中生成事件 例如单击鼠标 但无需实际使用鼠标 有什么好的方法
  • NSUserNotificationCenter.defaultUserNotificationCenter() 使用 PyInstaller 返回 None

    我正在尝试将通知发送到通知中心 Mac OSX 我正在使用 PyObjC 绑定来使用我们的 python 应用程序中的 cocoa api 我正在使用以下代码片段 import Foundation import objc NSUserNo
  • 如何知道python运行脚本的路径?

    sys arg 0 给我 python 脚本 例如 python hello py 返回 sys arg 0 的 hello py 但我需要知道 hello py 位于完整路径中的位置 我怎样才能用Python做到这一点 os path a
  • 列表推导式和 for 循环中的 Lambda 表达式[重复]

    这个问题在这里已经有答案了 我想要一个 lambda 列表 作为一些繁重计算的缓存 并注意到这一点 gt gt gt j for j in lambda i for i in range 10 9 9 9 9 9 9 9 9 9 9 Alt
  • 无法通过 Android 应用程序访问我的笔记本电脑的本地主机

    因此 我在发布此内容之前做了一项研究 我发现的解决方案不起作用 更准确地说 连接到我的笔记本电脑的 IPv4192 168 XXX XXX 没用 连接到10 0 2 2 加上端口 不起作用 我需要测试使用 Django Rest 框架构建的
  • 在 django 中导入设置时出现奇怪的错误

    我有很多项目在 ubuntu 中使用 python2 7 和 virtualenv virtualenvwrapper 工作 在我的工作中 一些开发人员使用 macosx 和 windows 通常我像往常一样创建项目 django admi
  • 不要模拟值对象:过于通用的规则,没有解释

    以下是 Mockito 单元测试框架的引用 不要模拟值对象 为什么有人会想要这样做呢 因为实例化对象太痛苦了 gt 无效 原因 如果创造新的装置太困难 那就是一个迹象 代码可能需要一些认真的重构 另一种方法是创建 价值对象的构建者 有一些工
  • Eclipse/PyDev 中未使用导入警告,尽管已使用

    我正在我的文件中导入一个绘图包 如下所示 import matplotlib pyplot as plt 稍后我会在我的代码中成功使用此导入 fig plt figure figsize 16 10 然而 Eclipse 告诉我 未使用的导
  • 将图与热图(可能是对数)配对?

    How to create a pair plot in Python like the following but with heat maps instead of points or instead of a hex bin plot
  • 在Python中使用pil读取tif图像时出现值错误?

    我必须读取尺寸的tif图像2200 2200并输入 uint16 我将 PIL 库与 anaconda python 一起使用 如下所示 from PIL import Image img Image open test tif img i
  • SQLAlchemy 与 count、group_by 和 order_by 使用 ORM

    我有几个函数需要使用 count group by 和 order by 进行一对多连接 我使用 sqlalchemy select 函数生成一个查询 该查询将返回一组 id 然后我对其进行迭代以对各个记录执行 ORM 选择 我想知道是否有
  • PyQt5按钮lambda变量变成布尔值[重复]

    这个问题在这里已经有答案了 当我运行下面的代码时 它显示如下 为什么 x 不是 x 而是变成布尔值 这种情况仅发生在传递到用 lambda 调用的函数中的第一个参数上 错误的 y home me model some file from P
  • 从 Django 运行 shell 命令

    我正在 Django 中开发一个网页 使用 apache 服务器 需要调用 shell 命令来启用 禁用一些守护进程 我尝试这样做 os system service httpd restart 1 gt HOME out 2 gt HOM
  • 超过两个点的Python相对导入

    是否可以使用路径中包含两个以上点的模块引用 就像这个例子一样 Project structure sound init py codecs init py echo init py nix init py way1 py way2 py w

随机推荐