如何在 Unittest 上断言可迭代对象不为空?
How to assert that an iterable is not empty on Unittest?
向服务提交查询后,我得到字典或列表,我想确保它不为空。我使用 Python 2.7.
令我惊讶的是 unittest.TestCase
class 实例没有任何 assertEmpty
方法。
现有的替代方案看起来不对:
self.assertTrue(bool(d))
self.assertNotEqual(d,{})
self.assertGreater(len(d),0)
Python unittest 框架是否缺少这种方法?如果是,那么断言可迭代对象不为空的最 pythonic 方法是什么?
也许:
self.assertRaises(StopIteration, next(iterable_object))
空 lists/dicts 评估为 False,因此 self.assertTrue(d)
完成了工作。
具体取决于您要查找的内容。
如果你想确保对象是可迭代的且不为空:
# TypeError: object of type 'NoneType' has no len()
# if my_iterable is None
self.assertTrue(len(my_iterable))
如果被测对象可以None
:
self.assertTrue(my_maybe_iterable)
Python
中的“虚假”值
A falsy (sometimes written falsey) value is a value that is considered false when encountered in a Boolean context.
根据 official doc,以下内置类型的计算结果为 false:
- 常量定义为假:
None
和 False
。
- 任何数字类型的零:
0
、0.0
、0j
、Decimal(0)
、Fraction(0, 1)
- 空序列和集合:
''
、()
、[]
、{}
、set()
、range(0)
因此,可以检查
- 非空 with
assertTrue()
and for
- 空虚 与
assertFalse()
.
(官方文档有所有可用的完整列表 assert methods。)
清洁代码
所有这些 assertTrue()
和 assertFalse()
调用都具有误导性,因为我们想要检查是否为空,并且需要知道哪些类型的计算结果为 false
才能正确理解其中发生的事情测试。
所以,为了干净的代码和更好的可读性,我们可以简单地定义我们自己的 assertEmpty()
和 assertNotEmpty()
方法,如下所示:
def assertEmpty(self, obj):
self.assertFalse(obj)
def assertNotEmpty(self, obj):
self.assertTrue(obj)
这一切都归功于 winklerrr,我只是在扩展他的想法:在需要 assertEmpty 或 assertNotEmpty 时使用可导入的 mixins:
class AssertEmptyMixin( object ):
def assertEmpty(self, obj):
self.assertFalse(obj)
class AssertNotEmptyMixin( object ):
def assertNotEmpty(self, obj):
self.assertTrue(obj)
注意,mixins 应该放在左边:
class MyThoroughTests( AssertNotEmptyMixin, TestCase ):
def test_my_code( self ):
...
self.assertNotEmpty( something )
基于@winklerr 的回答和@Merk 的评论,我首先扩展了检查给定对象是否为 Container
的想法。
from typing import Container
def assertContainerEmpty(self, obj: Container) -> None:
"""Asserts whether the given object is an empty container."""
self.assertIsInstance(obj, Container)
self.assertFalse(obj)
def assertContainerNotEmpty(self, obj: Container) -> None:
"""Asserts whether the given object is a non-empty container."""
self.assertIsInstance(obj, Container)
self.assertTrue(obj)
这意味着如果给定的对象是例如 assertEmpty
和 assertNotEmpty
将始终失败。 float
或用户定义的实例 class - 无论它是否会正确计算为 True
/False
.
与已经提出的答案略有不同...如果绝对需要特定的命名断言,您可以子class TestCase
并在其中添加新断言的方法。
from pathlib import Path
from typing import Container
from unittest import TestCase
class BaseTestCase(TestCase):
def assertIsFile(self, path: str, msg: str=None) -> None:
default_msg = 'File does not exist: {0}'.format(path)
msg = msg if msg is not None else default_msg
if not Path(path).resolve().is_file():
raise AssertionError(msg)
def assertIsEmpty(self, obj: Container, msg: str=None) -> None:
default_msg = '{0} is not empty.'.format(obj)
msg = msg if msg is not None else default_msg
self.assertIsInstance(obj, Container, '{0} is not a container.'.format(obj))
if len(obj) > 0:
raise AssertionError(msg)
def assertIsNotEmpty(self, obj: Container, msg: str=None) -> None:
default_msg = '{0} is empty.'.format(obj)
msg = msg if msg is not None else default_msg
self.assertIsInstance(obj, Container, '{0} is not a container.'.format(obj))
if obj is None or len(obj) == 0:
raise AssertionError(msg)
然后子class 新的 BaseTestCase
class 以使用新的断言方法。
class TestApplicationLoadBalancer(_BaseTestCase):
def setUp(self) -> None:
# These assertions will fail.
self.assertIsFile('does-not-exist.txt')
self.assertIsEmpty(['asdf'])
self.assertIsNotEmpty([])
就像 built-in unittest
断言一样,如果需要,您可以向这些断言传递错误消息。
class TestApplicationLoadBalancer(_BaseTestCase):
def setUp(self) -> None:
# These assertions will fail.
self.assertIsFile('does-not-exist.txt', 'Foo')
self.assertIsEmpty(['asdf'], 'Bar')
self.assertIsNotEmpty([], 'Baz')
向服务提交查询后,我得到字典或列表,我想确保它不为空。我使用 Python 2.7.
令我惊讶的是 unittest.TestCase
class 实例没有任何 assertEmpty
方法。
现有的替代方案看起来不对:
self.assertTrue(bool(d))
self.assertNotEqual(d,{})
self.assertGreater(len(d),0)
Python unittest 框架是否缺少这种方法?如果是,那么断言可迭代对象不为空的最 pythonic 方法是什么?
也许:
self.assertRaises(StopIteration, next(iterable_object))
空 lists/dicts 评估为 False,因此 self.assertTrue(d)
完成了工作。
具体取决于您要查找的内容。
如果你想确保对象是可迭代的且不为空:
# TypeError: object of type 'NoneType' has no len()
# if my_iterable is None
self.assertTrue(len(my_iterable))
如果被测对象可以None
:
self.assertTrue(my_maybe_iterable)
Python
中的“虚假”值A falsy (sometimes written falsey) value is a value that is considered false when encountered in a Boolean context.
根据 official doc,以下内置类型的计算结果为 false:
- 常量定义为假:
None
和False
。 - 任何数字类型的零:
0
、0.0
、0j
、Decimal(0)
、Fraction(0, 1)
- 空序列和集合:
''
、()
、[]
、{}
、set()
、range(0)
因此,可以检查
- 非空 with
assertTrue()
and for - 空虚 与
assertFalse()
.
(官方文档有所有可用的完整列表 assert methods。)
清洁代码
所有这些 assertTrue()
和 assertFalse()
调用都具有误导性,因为我们想要检查是否为空,并且需要知道哪些类型的计算结果为 false
才能正确理解其中发生的事情测试。
所以,为了干净的代码和更好的可读性,我们可以简单地定义我们自己的 assertEmpty()
和 assertNotEmpty()
方法,如下所示:
def assertEmpty(self, obj):
self.assertFalse(obj)
def assertNotEmpty(self, obj):
self.assertTrue(obj)
这一切都归功于 winklerrr,我只是在扩展他的想法:在需要 assertEmpty 或 assertNotEmpty 时使用可导入的 mixins:
class AssertEmptyMixin( object ):
def assertEmpty(self, obj):
self.assertFalse(obj)
class AssertNotEmptyMixin( object ):
def assertNotEmpty(self, obj):
self.assertTrue(obj)
注意,mixins 应该放在左边:
class MyThoroughTests( AssertNotEmptyMixin, TestCase ):
def test_my_code( self ):
...
self.assertNotEmpty( something )
基于@winklerr 的回答和@Merk 的评论,我首先扩展了检查给定对象是否为 Container
的想法。
from typing import Container
def assertContainerEmpty(self, obj: Container) -> None:
"""Asserts whether the given object is an empty container."""
self.assertIsInstance(obj, Container)
self.assertFalse(obj)
def assertContainerNotEmpty(self, obj: Container) -> None:
"""Asserts whether the given object is a non-empty container."""
self.assertIsInstance(obj, Container)
self.assertTrue(obj)
这意味着如果给定的对象是例如 assertEmpty
和 assertNotEmpty
将始终失败。 float
或用户定义的实例 class - 无论它是否会正确计算为 True
/False
.
与已经提出的答案略有不同...如果绝对需要特定的命名断言,您可以子class TestCase
并在其中添加新断言的方法。
from pathlib import Path
from typing import Container
from unittest import TestCase
class BaseTestCase(TestCase):
def assertIsFile(self, path: str, msg: str=None) -> None:
default_msg = 'File does not exist: {0}'.format(path)
msg = msg if msg is not None else default_msg
if not Path(path).resolve().is_file():
raise AssertionError(msg)
def assertIsEmpty(self, obj: Container, msg: str=None) -> None:
default_msg = '{0} is not empty.'.format(obj)
msg = msg if msg is not None else default_msg
self.assertIsInstance(obj, Container, '{0} is not a container.'.format(obj))
if len(obj) > 0:
raise AssertionError(msg)
def assertIsNotEmpty(self, obj: Container, msg: str=None) -> None:
default_msg = '{0} is empty.'.format(obj)
msg = msg if msg is not None else default_msg
self.assertIsInstance(obj, Container, '{0} is not a container.'.format(obj))
if obj is None or len(obj) == 0:
raise AssertionError(msg)
然后子class 新的 BaseTestCase
class 以使用新的断言方法。
class TestApplicationLoadBalancer(_BaseTestCase):
def setUp(self) -> None:
# These assertions will fail.
self.assertIsFile('does-not-exist.txt')
self.assertIsEmpty(['asdf'])
self.assertIsNotEmpty([])
就像 built-in unittest
断言一样,如果需要,您可以向这些断言传递错误消息。
class TestApplicationLoadBalancer(_BaseTestCase):
def setUp(self) -> None:
# These assertions will fail.
self.assertIsFile('does-not-exist.txt', 'Foo')
self.assertIsEmpty(['asdf'], 'Bar')
self.assertIsNotEmpty([], 'Baz')