在python中测试返回iterable的函数

2024-04-25 15:25:01 发布

您现在位置:Python中文网/ 问答频道 /正文

我在测试python函数时遇到了一些困难 返回iterable,就像 产生只返回iterable的or函数,如return imap(f, some_iter)或{}。在

所以在置换的例子中,我希望函数的输出是[(1, 2, 3), (1, 3, 2), ...]。所以,我开始测试我的代码。在

def perm3():
  return permutations([1,2,3])

# Lets ignore test framework and such details
def test_perm3():
  assertEqual(perm3(), [(1, 2, 3), (1, 3, 2), ...])

这行不通,因为perm3()是一个iterable,而不是一个 列表。所以我们可以修正这个特殊的例子。在

^{pr2}$

这个很好用。但是如果我嵌套了iterable呢?那就是 它能让它产生吗?比如说这些表情 product(permutations([1, 2]), permutations([3, 4]))。现在这是 可能没用,但很明显它会(一旦展开 迭代器)类似[((1, 2), (3, 4)), ((1, 2), (4, 3)), ...]的东西。 然而,我们不能仅仅将list包装在我们的结果上,因为这只会 将iterable<blah>转到{}。嗯 当然我可以做map(list, product(...)),但这只适用于 嵌套级别为2。在

那么,python测试社区有没有针对 测试iterables时出现问题?当然有些东西不能 以这种方式进行测试,就像你想要一个无限的发电机,但是 不过,这个问题应该足够普遍,有人会想 关于这个。在


Tags: or函数代码testreturndefsomeproduct
3条回答

我使用KennyTM's assertRecursiveEq

import unittest
import collections
import itertools

class TestCase(unittest.TestCase):
    def assertRecursiveEq(self, first, second, *args, **kwargs):
        """
        https://stackoverflow.com/a/3124155/190597 (KennyTM)
        """
        if (isinstance(first, collections.Iterable)
            and isinstance(second, collections.Iterable)):
            for first_, second_ in itertools.izip_longest(
                    first, second, fillvalue = object()):
                self.assertRecursiveEq(first_, second_, *args, **kwargs)
        else:
            # If first = np.nan and second = np.nan, I want them to
            # compare equal. np.isnan raises TypeErrors on some inputs,
            # so I use `first != first` as a proxy. I avoid dependency on numpy
            # as a bonus.
            if not (first != first and second != second):
                self.assertAlmostEqual(first, second, *args, **kwargs)                

def perm3():
    return itertools.permutations([1,2,3])

class Test(TestCase):
    def test_perm3(self):
        self.assertRecursiveEq(perm3(),
            [(1, 2, 3), (1, 3, 2), (2, 1, 3), (2, 3, 1), (3, 1, 2), (3, 2, 1)])

if __name__ == '__main__':
    import sys
    sys.argv.insert(1, '--verbose')
    unittest.main(argv = sys.argv)

您可以将建议扩展为包括type(这允许您区分列表、元组等),如下所示:

def unroll(item):
  if "__iter__" in dir(item):
    return map(unroll, item), type(item)
  else:
    return item, type(item)

例如:

^{pr2}$

一。在

值得一提的是,type在区分对象方面是粗糙的,例如<type 'classobj'>。。。在

1。如果结果的顺序无关紧要

使用unittest.assertItemsEqual()。这将测试项是否同时存在于self和reference中,但忽略顺序。这在您的示例中起作用—一个嵌套的深层示例。它也适用于我编造的一个2层深的例子。在

2。如果结果的顺序很重要

我建议不要将perm3()的结果强制转换到列表中。相反,在迭代时直接比较元素。下面是一个测试函数,可以在您的示例中使用。我把它添加到unittest.TestCase公司名称:

def assertEqualIterables(self, itable1, itable2):
     for ival1, ival2 in zip(itable1, itable2):
         if "__iter__" in dir(ival1):
             self.assertEqualIterables(ival1, ival2)
         else:
             self.assertEquals(ival1, ival2)

使用方式如下:

^{pr2}$

相关问题 更多 >