【问题标题】:Can I run unittest / pytest with python Optimization on?我可以使用 python 优化运行 unittest / pytest 吗?
【发布时间】:2022-01-16 07:53:48
【问题描述】:

我刚刚在类的构造函数中添加了一些assert 语句。

这立即导致大约 10 次测试失败。

与其摆弄那些测试,我只想让 pytest 在 Python 的优化开启(-O 开关,这意味着 asserts 都被忽略)的情况下运行应用程序代码(显然不是测试代码)。但是查看文档和搜索我找不到这样做的方法。

我有点想知道这是否是一种不好的做法,因为可以说是在测试期间查看 asserts 是否失败。

另一方面,另一个想法是您可能有某些测试(集成测试等)应该在没有优化的情况下运行,以便asserts 生效,以及其他测试您对正在创建的对象不那么谨慎,忽略asserts 可能是合理的。

asserts 显然符合“测试的一部分”...变得更加复杂。

【问题讨论】:

  • 为什么不修复断言失败的代码?您要么在代码中发现错误,要么失败的断言毫无意义,应该被删除。
  • 我试图解释一下:这将涉及对传递的参数更加谨慎。当您将 Mock 作为参数传递时,您只需为其提供尽可能少的特征以使其充当假对象。
  • 如果值得添加断言,则值得正确配置您的 Mock。
  • 有趣的想法,但我不确定我是否同意:我认为asserts 本身就是质量检查:他们不一定要与测试合作。跨度>
  • 如果您正在挑选可以忽略特定测试的先决条件,那么您的测试是脆弱的。仅仅因为期望Foo 类型参数的函数不使用Foo 实例的每个 功能并不意味着您应该采取捷径并提供损坏的Foo 进行测试.

标签: python optimization pytest python-unittest assert


【解决方案1】:

在这种情况下,最好的方法是将所有断言语句移动到测试代码中。甚至可能切换到 https://pytest.org/,因为它已经在使用 assert 进行测试评估。

【讨论】:

  • 谢谢。我已经在使用 pytest。因此,您建议基本上为我要对参数运行检查的每个方法/构造函数创建一个测试,并从应用程序代码中完全删除 asserts。这是一种可能性……但例如,更复杂的测试、集成测试等,将不会受益于参数检查。当应用程序本身以“关闭”的优化运行时也不是。
  • 如果这些断言对生产代码有用并且您不希望它们被禁用,那么更好的方法是将它们变成 ifs。但是将它们保留在生产代码中并在测试时通过优化标志禁用它们会破坏它们的目的。
【解决方案2】:

我假设你实际上不能这样做。

弗洛林和切普纳都让我想知道这是否以及在多大程度上是可取的。但是可以想象各种模拟这样的事情的方法,例如 Verifier 类:

class ProjectFile():
    def __init__(self, project, file_path, project_file_dict=None):
        self.file_path = file_path
        self.project_file_dict = project_file_dict
        if __debug__:
            Verifier.check(self, inspect.stack()[0][3]) # gives name of method we're in

class Verifier():
    @staticmethod
    def check(object, method, *args, **kwargs):
        print(f'object {object} method {method}')
        if type(object) == ProjectFile:
            project_file = object
            if method == '__init__':
                # run some real-world checks, etc.:
                assert project_file.file_path.is_file()
                assert project_file.file_path.suffix.lower() == '.docx'
                assert isinstance(project_file.file_path, pathlib.Path)
                if project_file.project_file_dict != None:
                    assert isinstance(project_file.project_file_dict, dict)

然后你可以在测试代码中轻松地修补Verifier.check方法:

def do_nothing(*args, **kwargs):
    pass
verifier_class.Verifier.check = do_nothing

...所以您甚至不必将您的方法与另一个夹具或其他东西混在一起。显然,您可以逐个模块地执行此操作,因此,正如我所说,某些模块可能会选择不执行此操作(集成测试等)

【讨论】:

  • 尽管这可能有效,但它只是混淆了编码。您在此处作为示例提供的检查绝对属于生产代码。如果您担心“混乱”,那么将初始化期间的常见验证行为转移到基类或特殊的 mixin 类中是最具表现力的选择。
  • Mixin 只是一个基类,它添加了一个非常具体的特性。如果我们正在考虑您的检查,也许值得将检查拆分为几个类:AcceptsDocx 在其中您仅定义 init 方法,如果某些参数不是具有 .docx 扩展名的有效文件,则会引发异常。使用这种方法,您可以将此类检查移到外部,但仍保留运行它们的价值,并让您有机会命名它们并在需要的地方应用。
  • 顺便说一句,虽然你说这些检查“绝对属于生产代码”,但如果它们是孤立的,那可能是真的......但实际上创建 ProjectFile 的代码没有办法传递不是dict 的第三个参数,或者实际上不是现有文件的pathlib.Path(某些测试除外)。因此,这些asserts 可以作为故障保险,防止未来的代码修改。
  • 好的,您最初的问题表明您正在寻找最佳实践。然而,现实生活中的每一个背景都可能有一些特殊的东西,现在我明白了它的目的。
猜你喜欢
  • 1970-01-01
  • 2013-09-20
  • 2011-04-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-04-29
  • 1970-01-01
相关资源
最近更新 更多