Я ищу метод (если доступен), который может сравнивать два значения и вызывать ошибку утверждения со значимым сообщением, когда сравнение не удается.
Если я использую 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()
, которые можно легко использовать без дополнительных ограничений?
@AbdulNiyasPM: Тоже не работает. Та же ошибка: ValueError: no such test method in <class 'unittest.TestCase'>: runTest
Вы должны передать сообщение утверждения вручную:
assert a == b, '%s != %s' % (a, b)
# AssertionError: 3 != 4
Да, именно так. Однако это очень много лишнего набора :) Фактически, дополнительного набора текста без добавления дополнительной "информации" в исходный код. Если ничего не выходит, то я подумываю создать свою крошечную библиотеку для такой упаковки :).
вы смотрели numpy.testing?
https://docs.scipy.org/doc/numpy-1.13.0/reference/routines.testing.html
Среди прочего в нем есть: assert_almost_equal (фактический, желаемый [, ...]) Вызывает ошибку AssertionError, если два элемента не равны с требуемой точностью.
Это assert выводит на печать фактическое и желаемое. Если вы увеличиваете точность, сравнение будет произвольно близко к == (для чисел с плавающей запятой)
Интересно. numpy.testing
раньше не проверял. У них тоже есть assert_equal()
! Однако у них нет assertXxx (), предлагаемого unittest.TestCase
.
Можно создать новый модуль «помощник», который предоставляет доступ к функциям утверждения. 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
, например:
AssertsAccessor.assertEquals(1, 2)
AssertionError: 1 != 2
Или другой пример:
AssertsAccessor.assertGreater(1, 2)
Какие результаты:
AssertionError: 1 not greater than 2
Если предположить, что модуль, созданный для средства доступа, называется assertions
, общее использование в коде будет выглядеть так:
from assertions import AssertsAccessor
def foo(small_arg, big_arg):
AssertsAccessor.assertGreater(big_arg, small_arg)
# some logic here
У меня было подобное в прошлом, и в конце концов я написал короткое настраиваемое утверждение, которое принимает любое условие в качестве ввода.
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
Это тоже интересная идея. Спасибо. Добро пожаловать в SO.
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.
unittest.TestCase().assertEqual(a, b)
пробовали?