如何在没有太多负担的情况下使用`assertEqual()`[或同等功能]?

时间:2018-10-20 15:07:11

标签: python assert python-unittest

我正在寻找一种方法(如果可用),该方法可以比较两个值并在比较失败时通过有意义的消息引发断言错误。

如果我使用assert,则失败消息将不包含断言失败时进行比较的值。

>>> a = 3
>>> b = 4
>>> assert a == b
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AssertionError
>>> 

如果我使用assertEqual()包中的unittest.TestCase方法,则声明消息将包含已比较的值。

        a = 3
        b = 4
>       self.assertEqual(a, b)
E       AssertionError: 3 != 4

请注意,此处的断言错误消息包含已比较的值。这在现实生活中非常有用,因此对我来说是必需的。普通的assert(请参见上文)不会这样做。

但是,到目前为止,我只能在继承自assertEqual()并提供诸如unittest.TestCase之类的其他必需方法的类中使用runTest()。我想在任何地方都使用assertEqual(),不仅在继承的类中使用。那可能吗?

我尝试了以下方法,但它们没有起作用。

>>> import unittest
>>> unittest.TestCase.assertEqual(a, b)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unbound method failUnlessEqual() must be called with TestCase instance as first argument (got int instance instead)
>>> 
>>> 
>>> tc = unittest.TestCase()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib64/python2.6/unittest.py", line 215, in __init__
    (self.__class__, methodName)
ValueError: no such test method in <class 'unittest.TestCase'>: runTest
>>> 

是否有其他软件包或库提供类似assertEqual()的类似方法,可以轻松使用而没有附加约束?

5 个答案:

答案 0 :(得分:3)

您必须手动提供断言消息:

assert a == b, '%s != %s' % (a, b)
# AssertionError: 3 != 4

答案 1 :(得分:2)

可以创建一个“帮助程序”新模块,以提供对断言函数的访问。 AssertsAccessor在这种情况下:

from unittest import TestCase

# Dummy TestCase instance, so we can initialize an instance
# and access the assert instance methods
class DummyTestCase(TestCase):
    def __init__(self):
        super(DummyTestCase, self).__init__('_dummy')

    def _dummy(self):
        pass

# A metaclass that makes __getattr__ static
class AssertsAccessorType(type):
    dummy = DummyTestCase()

    def __getattr__(cls, key):
        return getattr(AssertsAccessor.dummy, key)

# The actual accessor, a static class, that redirect the asserts
class AssertsAccessor(object):
    __metaclass__ = AssertsAccessorType

只需创建模块一次,然后就可以访问unittest软件包中的所有 asserts ,例如:

AssertsAccessor.assertEquals(1, 2)
  

AssertionError:1!= 2

或者另一个例子:

AssertsAccessor.assertGreater(1, 2)

哪个结果:

  

AssertionError:1不大于2

假设为访问器创建的模块名为assertions,则代码中的常见用法如下:

from assertions import AssertsAccessor

def foo(small_arg, big_arg):
    AssertsAccessor.assertGreater(big_arg, small_arg)
    # some logic here

答案 2 :(得分:1)

您看过numpy.testing吗?

https://docs.scipy.org/doc/numpy-1.13.0/reference/routines.testing.html

它具有以下优点: assert_almost_equal(actual,required [,...])如果两个项不等于期望的精度,则引发AssertionError。

此断言打印出实际的和所需的。如果您提高精度,则比较会任意接近==(对于浮点数)

答案 3 :(得分:1)

过去我有相似之处,最终我写了简短的自定义断言,接受任何条件作为输入。

import inspect

def custom_assert(condition):
    if not condition:
        frame = inspect.currentframe()
        frame = inspect.getouterframes(frame)[1]
        call_signature = inspect.getframeinfo(frame[0]).code_context[0].strip()

        import re
        argument = re.search('\((.+)\)', call_signature).group(1)
        if '!=' in argument:
            argument = argument.replace('!=','==')
        elif '==' in argument:
            argument = argument.replace('==','!=')
        elif '<' in argument:
            argument = argument.replace('<','>=')
        elif '>' in argument:
            argument = argument.replace('>','<=')
        elif '>=' in argument:
            argument = argument.replace('>=','<')
        elif '<=' in argument:
            argument = argument.replace('<=','>')

        raise AssertionError(argument)

if __name__ == '__main__':
    custom_assert(2 == 1)

输出:

Traceback (most recent call last):
  File "custom_assert.py", line 27, in <module>
    custom_assert(2 == 1)
  File "custom_assert.py", line 24, in custom_assert
    raise AssertionError(argument)
AssertionError: 2 != 1

答案 4 :(得分:0)

assertEqual或任何其他assertXxx()方法都希望第一个参数是对象引用。通常,我们将该方法称为self.assertEqual(first, second, msg=None)。 这里self满足第一个预期参数。为了避免这种情况,我们可以执行以下操作:

from unittest import TestCase as tc
def some_func():
    dummy_obj = tc()
    tc.assertEqual(dummy_obj, 123, 123, msg='Not Equal')

此行为的原因是XUnit框架中的宿醉。