【问题标题】:How to assert that an iterable is not empty on Unittest?如何断言 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 方式是什么?

【问题讨论】:

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

标签: python python-2.7 unit-testing python-unittest assertion


【解决方案1】:

Python 中的“假”值

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

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

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

因此,可以检查

(官方文档有所有可用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.
        • 这行得通,但不符合最小意外原则,通常在单元测试中清晰胜过简洁。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2019-05-31
        • 1970-01-01
        • 2021-07-03
        • 2023-03-07
        • 1970-01-01
        • 2021-10-25
        • 1970-01-01
        相关资源
        最近更新 更多