5

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

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

4

2 回答 2

3

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

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


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

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


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

如果你想测试 ABC 的意思,defuz 的答案非常接近,而且我认为他或其他人可以通过更多的工作来完成它。


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

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


实际的具体类在协议之上有额外的接口,您可能想要测试,但这更难描述。特别是,方法__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 定义了一个具体对象层,尽管它不具有权威性,但与之前的定义相匹配,并且定义更加严格。

不幸的是,这个测试对你来说肯定不是很有用,因为它们正在检查诸如是否PyDict_CheckPyDict_GetItem在你的类上工作之类的东西,它们不会用于纯 Python 中定义的任何映射。


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

于 2013-05-16T18:44:11.113 回答
0

基于 ABC 模块的标准模块中有抽象基类。collections

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

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
于 2013-05-16T18:18:39.653 回答