一个相当小的问题:有没有人知道预先制作的Python单元测试套件,只检查一个类是否符合标准Python数据结构接口之一(例如,列表,集合,字典,队列等) 。写它们并不是很难,但是如果有人已经这样做的话,我不愿意这样做。这似乎是某人可能已经完成的非常基本的功能。
用例是由于与平台相关的不同限制,我使用工厂模式来创建数据结构。因此,我需要能够测试生成的对象仍然符合表面上的标准接口。此外,我应该注意,通过“符合”,我的意思是测试不仅要检查接口函数是否存在,还要检查它们是否有效(例如,可以设置和检索映射中的值)。 Python 2.7测试将是首选。
答案 0 :(得分:3)
首先,“标准Python数据结构接口”不是列表,集合,字典,队列等。这些是接口的特定实现。 (并且队列甚至不是您正在考虑的意义上的数据结构 - 其显着特征是其操作是原子的,并且put
和get
可选地在Condition
上同步等等。)
无论如何,接口是以五种不同的不兼容方式定义的。
文档的Built-in Types部分描述了迭代器类型,序列类型等的含义。然而,这些并不像您期望的参考文档那么严格(至少如果你“习惯了,比方说,C ++或Java。”
我不知道对这样的事情有任何测试,所以我认为你必须从头开始构建它们。
collections
模块包含定义接口的Collections Abstract Base Classes,并提供通过abc
module注册“虚拟子类”的方法。因此,您可以通过继承collections.Mapping
或调用collections.Mapping.register
来声明“我是映射”。但这实际上并不能证明你是一个映射,就像你声称的那样。 (如果您继承自Mapping
,它还可以充当mixin,通过在__contains__
之上实施__getitem__
来帮助您完成界面。)
如果你想测试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)
1}},或Foo({key: value})
或Foo([(key, value)])
。
对于这种情况,是所有标准Python实现附带的现有测试。 CPython附带了一个非常广泛的测试套件,其中包括test_dict.py
之类的内容。 PyPy运行所有(Python级)CPython测试,还有一些额外的测试。
您显然必须修改这些测试以在任意类上运行而不是在测试中硬编码,并且您可能还必须修改它们以处理您选择的任何定义。此外,他们可能会测试更多而不是您的要求。你只想知道一个类是否符合协议,而不是它的方法是否正确,对吧?但是,我认为它们是一个很好的起点。
最后,C API定义了一个Concrete Objects Layer,虽然它不具有权威性,但它与之前的定义相匹配,并且更严格地定义。
不幸的是,这个测试肯定对你不是很有用,因为他们正在检查PyDict_Check
和PyDict_GetItem
是否适合你class,它们不会用于纯Python中定义的任何映射。
如果您确实为这些定义构建了完整的内容,我强烈建议将其放在PyPI上,并将其发布到python-list,以便获得反馈(以及错误报告)。
答案 1 :(得分:0)
基于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