如何断言 Unittest 上的可迭代对象不为空?

Posted

技术标签:

【中文标题】如何断言 Unittest 上的可迭代对象不为空?【英文标题】:How to assert that an iterable is not empty on Unittest? 【发布时间】:2016-01-17 22:08:17 【问题描述】:

向服务提交查询后,我得到了一个字典或列表,我想确保它不为空。我使用 Python 2.7。

我很惊讶unittest.TestCase 类实例没有任何 assertEmpty 方法。

现有的替代品看起来不太对:

self.assertTrue(bool(d))
self.assertNotEqual(d,)
self.assertGreater(len(d),0)

Python unittest 框架中是否缺少这种方法?如果是,那么断言可迭代对象不为空的最pythonic 方式是什么?

【问题讨论】:

***.com/questions/53513/… 可能会有所帮助。 好链接!我知道如何测试可迭代对象是否为空;正在寻找专门的 unittest 断言方法......很惊讶没有 assertEmpty/assertNotEmpty 方法 - 恕我直言,它会大大提高可读性,而不是在代码周围都有 assertTrue 和 assertFalse...... 同意,只是觉得assertTrue 可能更干净一点。我认为我个人的偏好(也许是最具语义意义的选项)是断言 len != 0。我同意 assertEmpty/assertNotEmpty 方法在 unittest 框架中占有一席之地。 请注意,“iterable”比“lists or dictionaries”大得多,如果不实际迭代,一般无法判断可迭代对象是否为空。 【参考方案1】:

Python 中的“假”值

假(有时写成假)值是在布尔上下文中遇到时被认为是假的值。

根据official doc,以下内置类型评估为假:

定义为假的常量:NoneFalse。 任何数字类型的零:00.00jDecimal(0)Fraction(0, 1) 空序列和集合:''()[]set()range(0)

因此,可以检查

non-emptiness 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)

【讨论】:

在例如一个标量或对象被意外传递了? @Merk 是的,你是对的。但是,如果您仅出于私人原因使用这些辅助函数,那应该没问题,因为您知道这些函数的作用。如果此代码打算与其他开发人员一起在一个小项目中,您可能需要添加一些文档字符串来解释它的安全使用,或者只是正确地重命名函数(例如assert_list_empty(self, a_list))。或者,如果您打算将这些函数添加到您的第三方测试库中,只需添加一些代码以确保您处理所有可能的输入(通过添加 if ... elif ... else ... 和实例检查)【参考方案2】:

根据@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)

这意味着assertEmptyassertNotEmpty 如果给定对象是例如float,或用户定义类的实例 - 无论它是否会正确评估为 True/False

【讨论】:

【参考方案3】:

这一切都归功于 winklerrr,我只是在扩展他的想法:在需要 assertEmpty 或 assertNotEmpty 时使用可导入的 mixin:

class AssertEmptyMixin( object ):
    def assertEmpty(self, obj):
        self.assertFalse(obj)

class AssertNotEmptyMixin( object ):
    def assertNotEmpty(self, obj):
        self.assertTrue(obj)

注意,mixin 应该放在左边:

class MyThoroughTests( AssertNotEmptyMixin, TestCase ):
    def test_my_code( self ):
        ...
        self.assertNotEmpty( something )

【讨论】:

【参考方案4】:

也许:

self.assertRaises(StopIteration, next(iterable_object))

【讨论】:

一般来说这并不理想,因为它可能会消耗您随后需要查看的项目。 最好的一个班轮,因为它甚至适用于发电机。如果您正在测试一个空的可迭代对象,则不需要查看它的项目。 那不会捕获异常,你需要把它放在一个函数中。【参考方案5】:

完全取决于您在寻找什么。

如果你想确保对象是一个可迭代对象并且它不为空:

# TypeError: object of type 'NoneType' has no len()
# if my_iterable is None
self.assertTrue(len(my_iterable))

如果被测试的对象可以是None:

self.assertTrue(my_maybe_iterable)

【讨论】:

【参考方案6】:

空列表/字典评估为 False,因此 self.assertTrue(d) 完成工作。

【讨论】:

对。那么在 unittest 中没有断言方法可以检查空虚吗?在代码中到处都有 assertTrue 和 assertFalse 很烦人... 没有断言方法来检查是否为空 - unittest. 这行得通,但不符合最小意外原则,通常在单元测试中清晰胜过简洁。

以上是关于如何断言 Unittest 上的可迭代对象不为空?的主要内容,如果未能解决你的问题,请参考以下文章

内置函数和匿名函数

为啥 all() 为空的可迭代对象返回 True? [复制]

内置函数

如何判断Object对象不为空

junit测试assert各种断言用法

常用断言关键字(rf中)