【问题标题】:How to perform assert introspection in Python如何在 Python 中执行断言自省
【发布时间】:2016-11-18 17:23:51
【问题描述】:

我正在研究如何在 Python 中执行断言自省,方法与 that py.test does 相同。比如……

>>> a = 1
>>> b = 2
>>> assert a == b
Traceback (most recent call last):
 File "<stdin>", line 1, in <module>
AssertionError   # <--- I want more information here, eg 'AssertionError: 1 != 2'

我看到py.codehas some functionality around this 和我还看到this answer,注意到sys.excepthook 允许你插入任何你想要异常的行为,但我不清楚如何放置这一切都在一起。

【问题讨论】:

  • 为什么不使用pytest 本身?
  • @pylang 我可以重新使用 py.test 允许这种情况发生的部分,但我不能只使用 py.test 本身。出于我的问题的目的,我说你应该假设例如。我实际上并没有在这种情况下运行测试。
  • @pylang 实际上可以在一般上下文中使用 pytest 的断言吗?我假设 OP 希望在独立程序/库中使用该功能,例如,用于验证目的。
  • 我想我现在明白了。是的,我不相信 pytes 有交互模式(至少在 jupyter 笔记本中没有)。传统上,由于这个确切的问题,我使用了nose

标签: python assert pytest


【解决方案1】:

如果你想显示详细的错误信息,你可以这样做

def assertion(a,b):
    try:
        assert a==b
    except AssertionError as e:
        e.args += ('some other', 'information',)
        raise

a=1
b=2
assertion(a,b)

这段代码会给出这样的输出:

Traceback (most recent call last):
  File "tp.py", line 11, in <module>
    assertion(a,b)
  File "tp.py", line 4, in assertion
    assert a==b
AssertionError: ('some other', 'information')

【讨论】:

  • @Tom 。这有帮助吗?
  • 不是特别,不是,但还是很感激。这个答案在异常中添加了其他附加信息,但我感兴趣的是比较本身的状态。在这种情况下,这意味着包括 a 和 b 的值,并确定问题在于它们不相等。 (但一种通用方法也值得其他运营商使用)
【解决方案2】:

unittest 断言提供了额外的信息(可能比您需要的更多)。灵感来自 Raymond Hettinger 的 talk。 这是部分答案,仅给出 ab(输出的最后一行)的值,而不是您也在寻找的额外内省,这在 pytest 中是独一无二的。

import unittest

class EqualTest(unittest.TestCase):

    def testEqual(self, a, b):
        self.assertEqual(a, b)


a, b = 1, 2
assert_ = EqualTest().testEqual
assert_(a, b)

输出

---------------------------------------------------------------------------
AssertionError                            Traceback (most recent call last)
<ipython-input-4-851ce0f1f668> in <module>()
      9 a, b = 1, 2
     10 assert_ = EqualTest().testEqual
---> 11 assert_(a, b)

<ipython-input-4-851ce0f1f668> in testEqual(self, a, b)
      4 
      5     def testEqual(self, a, b):
----> 6         self.assertEqual(a, b)
      7 
      8 

C:\Anaconda3\lib\unittest\case.py in assertEqual(self, first, second, msg)
    818         """
    819         assertion_func = self._getAssertEqualityFunc(first, second)
--> 820         assertion_func(first, second, msg=msg)
    821 
    822     def assertNotEqual(self, first, second, msg=None):

C:\Anaconda3\lib\unittest\case.py in _baseAssertEqual(self, first, second, msg)
    811             standardMsg = '%s != %s' % _common_shorten_repr(first, second)
    812             msg = self._formatMessage(msg, standardMsg)
--> 813             raise self.failureException(msg)
    814 
    815     def assertEqual(self, first, second, msg=None):

AssertionError: 1 != 2

【讨论】:

  • 谢谢,在这种情况下,我特别感兴趣的是自省 assert 语句本身。
【解决方案3】:

我认为在独立上下文中重现 pytest 的断言自省并不简单。该文档包含更多关于其工作原理的details

pytest 在导入时重写测试模块。它通过使用导入钩子来编写新的 pyc 文件来做到这一点。大多数情况下,这是透明的。但是,如果您自己搞乱导入,导入钩子可能会干扰。如果是这种情况,只需使用 --assert=reinterp 或 --assert=plain。此外,如果无法写入新的 pycs,即在只读文件系统或 zipfile 中,重写将静默失败。

看起来需要相当多的技巧才能使其在任意模块中工作,因此您最好使用其他答案中建议的解决方案。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-10-07
    • 1970-01-01
    • 1970-01-01
    • 2010-11-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多