首页 > 解决方案 > 如何在批量 pytest 执行中使用对象的 __subclasses__() 方法?

问题描述

我正在为一些使用对象__subclasses__()方法的代码编写单元测试。最终,我试图__subclassess__()通过命名空间包来跟踪动态导入到我的应用程序中的类。

在某些情况下,我的代码库在 pytest 文件中创建了测试类。我的问题是,当我pytest在源目录上批量运行时,由于从这些一次性测试类中导入污染,我发现代码中出现故障或错误。这是因为 pytest 运行在运行源树时会维护所有导入。就其自身而言,测试可以通过,但它们会按顺序失败,有时取决于它们运行的​​顺序。

在我当前的代码分支中,这些__subclasses__()调用位于应用程序代码中,但我已将它们移到此处进行测试以使用 MVE 进行演示:

my/example.py

class MyClass(object):
    def __init__(self):
        pass


class MySubClass(MyClass):
    def __init__(self):
        super().__init__()

my/test_subclass.py

from my.example import MyClass


class TestSubClass(MyClass):
    def __init__(self):
        super().__init__()


def test_TestSubClass():
    assert issubclass(TestSubClass, MyClass)

my/test_subclasses.py

from my.example import MySubClass, MyClass


def test_find_subclasses():
    assert all([cls == MySubClass for cls in MyClass.__subclasses__()])

结果,当在我的机器上运行时,test_find_subclasses()由于发现TestSubClasswhen running after测试失败test_subclass.py

    def test_find_subclasses():
>       assert all([cls == MySubClass for cls in MyClass.__subclasses__()])
E       assert False
E        +  where False = all([True, False])

在排序的 pytest 运行期间保持“干净”状态的最佳方法是什么,这样我就可以避免导入错误?

标签: pythonpytest

解决方案


正如评论中所讨论的,您可能不想对可能扩展的类型进行硬编码MyClass,因为您真的无法预测您的应用程序将来需要什么。如果要检查子类化,只需检查它是否有效:

def test_find_subclasses():
    assert MySubClass in MyClass.__subclasses__()

更简洁地说,你可以简单地做

def test_find_subclasses():
    assert issubclass(MySubClass, MyClass)

话虽如此,您可以从技术上过滤您正在查看的类。在您的特定情况下,您有一个独特的命名约定,因此您可以执行类似的操作

def only_production_classes(iterable):
    return [cls for cls in iterable if not cls.__name__.lower().startswith('test')]

def test_find_subclasses():
    assert all([cls == MySubClass for cls in only_production_classes(MyClass.__subclasses__())])

您可以only_production_classes使用其他标准进行定义,例如该类出现的模块:

def only_production_classes(iterable):
    return [cls for cls in iterable if not cls.__module__.lower().startswith('test_')]

您不能轻易取消链接已加载的类对象,因此您对“干净”测试环境的想法不太可行。但是您确实可以选择根据数据的导入位置过滤您使用的数据。


推荐阅读