【问题标题】:Tests for Basic Python Data Structure Interfaces基本 Python 数据结构接口的测试
【发布时间】:2013-05-16 18:13:41
【问题描述】:

一个相当小的问题:有谁知道一套预制的 Python 单元测试套件,它只检查一个类是否符合标准 Python 数据结构接口之一(例如,列表、集合、字典、队列等) .编写它们并不太难,但是如果有人已经这样做了,我不想打扰这样做。这似乎是某人可能已经完成的非常基本的功能。

用例是由于与平台相关的不同限制,我正在使用工厂模式来创建数据结构。因此,我需要能够测试生成的对象是否仍然符合表面上的标准接口。另外,我应该注意,“符合”是指测试不仅要检查接口函数是否存在,还要检查它们是否工作(例如,可以在映射中设置和检索值)。首选 Python 2.7 测试。

【问题讨论】:

  • 我还没有看到一个很好的python工厂用例
  • 不知道有任何预制,但就像你说的那样,使用collections 中的 ABC 自己制作并不难
  • 附带说明,queue 并不是您想象中的数据结构,因为它的关键特性是它的多线程特性:所有操作都是原子的,它提供了一种方法让生产者或消费者相互阻止。
  • 同意队列不完全是一种数据结构。但是,它是我期望工厂需要提供的类型之一,所以我列出了它。
  • @Namey:但是如果你只是检查队列的协议,那几乎没有用。如果不适当同步,则不是队列。

标签: python testing data-structures


【解决方案1】:

首先,“标准的 Python 数据结构接口”不是列表、集合、字典、队列等。它们是接口的具体实现。 (队列甚至不是您所想的那种数据结构——它的显着特点是它的操作是原子的,putget 可以选择在Condition 上同步,等等。)

无论如何,接口以五种不同的不太兼容的方式定义。


文档的Built-in Types 部分描述了迭代器类型、序列类型等的含义。但是,这些并不像您对参考文档所期望的那样严格(至少如果您是过去,比如 C++ 或 Java)。

我不知道对这种东西有任何测试,所以我认为你必须从头开始构建它们。


collections 模块包含定义接口的Collections Abstract Base Classes,并提供了一种通过abc module 注册“虚拟子类”的方法。因此,您可以通过从collections.Mapping 继承或调用collections.Mapping.register 来声明“我是一个映射”。但这实际上并不能证明您一个映射,只是您声称自己是一个映射。 (如果你继承自Mapping,它也可以作为一个mixin,通过在__getitem__之上实现例如__contains__来帮助你完成接口。)

如果你想测试ABC的意思,defuz的答案非常接近,我认为他或其他人可以再多做一点工作。


CPython C API 定义了一个Abstract Objects Layer。虽然这实际上并不是该语言的权威,但显然 C-API 协议和语言级接口应该匹配。而且,与后者不同的是,前者是严格定义的。当然,来自CPython 2.7 的源代码,也许还有像PyPy 这样的其他实现,可能会有所帮助。

CPython 附带了一些测试,但实际上,它们用于测试从 C 调用 PyMapping_GetItem 在 Python 中正确调用你的 mymapping.__getitem__,这实际上与你想要测试的内容相切,所以我认为它不会有太大帮助。


实际的具体类在协议之上还有额外的接口,您可能想对其进行测试,但这很难描述。特别是,__new____init__ 方法的工作方式通常很重要。实现Mapping 协议意味着有人可以构造一个空的Foo 实例并使用foo[key] = value 向其中添加项目,但并不意味着有人可以构造Foo(key=value)Foo({key: value})Foo([(key, value)])

对于这种情况, 现有测试随所有标准 Python 实现一起提供。 CPython 带有一个非常广泛的测试套件,其中包括诸如test_dict.py 之类的东西。 PyPy 运行所有(Python 级别的)CPython 测试,以及一些额外的测试。

您显然必须修改这些测试以在任意类上运行而不是硬编码到测试中,并且您可能还必须修改它们以处理您选择的任何定义。另外,他们可能比您要求的测试更多。你只想知道一个类是否符合协议,而不是它的方法是否做正确的事,对吧?不过,我认为它们是一个很好的起点。


最后,C API 定义了一个Concrete Objects Layer,虽然它不具有权威性,但与之前的定义相匹配并且定义更严格。

不幸的是,这个测试肯定对你没有多大用处,因为他们正在检查诸如 PyDict_CheckPyDict_GetItem 是否在你的班级上工作,他们不会用于纯 Python 中定义的任何映射。


如果您确实为这些定义中的任何一个构建了完整的东西,我强烈建议将其放在 PyPI 上,并将其发布到 python-list,以便您获得反馈(和错误报告)。

【讨论】:

  • 几点注意事项: 1. 就我而言,最重要的是可以容纳集合 abc 中的任何虚拟子类以及 Queue 的测试。 2. test_dict.py 非常接近标记。通过一些小的编辑,我认为它可能很有用。 3. 如果没有人做过,我可能最终会根据 CPython 测试创建它们。 4. _new_,_init_,任何拆解的东西都不需要这些测试。我总是可以对测试进行子类化,为那些特定于实现的函数添加额外的检查。
  • 我接受这个已经足够好了。我已经进行了一些 cPython 测试并删除了一些基本依赖项。之后,我将使其全部设计为比较两个任意类,这两个类都是测试的类变量。这样,以列表为例,我可以让一个类是一个列表,而另一个类是一个任意的类,它应该像外部的列表一样(并且测试的子类可以覆盖要测试的类)。
【解决方案2】:

基于ABC模块的标准模块collections中有abstract base classes

您必须从这些类继承您的类,以确保您的类符合标准行为:

import collections

class MyDict(collections.Mapping):
    ...

另外,你可以测试已经存在的没有明显继承抽象类的类:

class MyPerfectDict(object):
    ... realization ...

def is_inherit(cls, abstract):
    try:
        class Test(abstract, cls): pass
        test = Test()
    except TypeError:
        return False
    else:
        return True

is_inherit(MyPerfectDict, Mapping) # False
is_inherit(dict, Mapping) # True

【讨论】:

  • 没错,但我认为它没有直接帮助。例如,如果我构建了一个完全符合Mapping 接口的类,但没有从collections.Mapping 继承或注册,collections 如何帮助您确定我的类是否可以接受?
  • @abarnert,我想我找到了一种方法,尽管它不是很好
  • 这并没有真正的帮助。如果MyPerfectDict 没有真正实现Mapping 协议,你的测试仍然会通过。
  • @abarnert,这个特定的示例可以正常工作,但是内置类存在问题,例如int。我不明白为什么。
  • 我认为您必须定义 Test.__new__Test.__init__ 以确保调用 ABC 的方法,然后它适用于所有类(甚至是内置类型)……但在你相信那模糊的回忆之前,让我做个实验吧……
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-12-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-06-16
相关资源
最近更新 更多