配置Pytest发现以忽略类名
Pytest 默认的查找规则会导入所有以 Test
开头的类,只要这些类没有 __init__()
方法。我遇到的情况是,这导致了一个错误的类被导入。
我正在测试一个使用 Factory Boy 的 Django 项目。http://factoryboy.readthedocs.org/en/latest/ 用来构建一个名为 Testimonial
的 Django 模型。
像这样:
class TestimonialFactory(factory.Factory):
class Meta:
model = models.Testimonial
问题在于 factory.Factory
没有 __init__()
方法。所以 py.test 看到 Test
imonials 就试图运行它。这就导致在 pytest 查找阶段试图往数据库里插入记录(结果搞得一团糟,失败不断)。
我通过修改 pytest.ini 文件,强制查找以 Check 开头的测试类,而不是以 Test 开头的类,来绕过这个问题:
[pytest]
python_classes=Check
但这并不是我真正想要的。我想知道有没有办法明确告诉 py.test 忽略某个特定名称的测试?
5 个回答
配置选项似乎只能使用前缀或通配符,所以我觉得你不能排除特定的文件名:https://pytest.org/latest/customize.html#confval-python_classes
我觉得把你的类(MyTestimonialFactory)重命名,或者把它移到发现路径之外,会是个简单的解决办法。
不过,我还是觉得你可以使用某个收集钩子,在收集过程中跳过或移除那个类。也许可以用 pytest_pycollect_makeitem
,具体可以参考这里:https://docs.pytest.org/en/latest/writing_plugins.html#collection-hooks
把所有的测试代码放到以 test_
开头的文件里,然后把下面这段内容加到你的 pytest.ini
文件中:
[pytest]
python_files=test_*.py
这样做是为了告诉 pytest 只去找那些以 test_*.py
命名的文件里的测试。
你应该使用pytest.ini文件,并通过通配符来匹配类名。
#pytest.ini file
[pytest]
python_classes = !Test
这样做会让pytest忽略所有以Test开头的测试类。
更多信息可以查看这里:https://docs.pytest.org/en/latest/example/pythoncollection.html#changing-naming-conventions
这是一个比较老的问题,但在StackOverflow上似乎是唯一相关的答案,所以我想在这里留下一个备用的解答,以备后用。
另一种解决方法是禁用所有基于类名的发现,只依赖子类的发现仅此而已。换句话说:
在你的配置文件中:(setup.cfg
或 pytest.ini
):
[pytest]
python_classes =
在你的测试文件中:
class TestWillNotBeRun(object):
# Not a subclass of unittest.TestCase, so not collected regardless of name
class TestWillBeRun(unittest.TestCase):
# Still okay to use TestName convention for readability
# It just doesn't actually do anything.
class StillGoingToBeRun(unittest.TestCase):
# Relying on subclassing means *all* subclasses will be picked up, regardless of name
这样做的一个好处是,你不需要更改你的非测试类的名称。对于一个对用户开放的库来说,不改名是有很好的理由的。此外,这样也不需要大规模重命名测试类(因为它们现在可以是任何名称)。最后,与基于名称的发现不同,非测试代码不太可能成为unittest.TestCase的子类。(当然,我相信总有例外。)
缺点是你必须确保所有的测试类都是unittest.TestCase
的子类。对我所有的代码来说,这已经是事实,所以没有额外的成本。不过,这并不一定适用于所有情况。
这里有一个我常用的简单解决方案,不过它会有一些额外的开销。
class DisablePyTestCollectionMixin(object):
__test__ = False
class TestimonialFactory(DisablePyTestCollectionMixin):
pass