找出函数有多少返回值

时间:2015-07-01 15:26:08

标签: python unit-testing

我正在为一些激光驱动器功能创建一些测试。对于某些激光器,支持一些子功能,在其他激光器上,我应该预期会出现错误(从而测试是否出现了错误)。 子功能当然(为了保持简单;-))不是1个功能,而是多个功能。因此,给定激光器,某个功能的测试应该通过或失败。

传递大小写不是问题,但是当它失败并且函数有多个返回值时,我们创建的泛型断言有一个问题,即它不知道应该返回到测试函数的返回值的数量因此,在激光器不支持子功能的情况下,我们的通用断言仅返回1无值。

因此,如果函数失败或通过,我们必须检查具有多个返回值的函数的测试,并且只能以正确的方式调用我们的泛型断言。 但这是一种丑陋的恕我直言,因为在这种情况下,我们检查子功能是否支持两次(通用断言的目标是在一个地方做到这一点)。

有没有办法确定函数预先调用函数的返回值的数量?

伪代码中的问题:

通用断言(加上测试的基本设置):

import functionality_under_test as fut

class Functionality( unittest.TestCase ):
    def shared_setup( self ):
        Functionality._issupported = fut.subfunctionality.is_supported()

    def _assert_sub_functionality( self, func, *args, **kwargs ):
        retval = None # We don't know how many retvals there will be

        if not self._issupported:
            # Here is the place where it should determine how many
            # return-values func really has and initialize retval as
            # with the correct number of None's in a tuple / one None.
            self.assert_raises( <expected error>, func, *args, **kwargs )
        else:
            # retval will be filled with either 1 value or a tuple by
            # successful call.
            retval = func( *args, **kwargs )

        return retval

对于具有1个返回值的函数,没有问题,因此我们可以这样做:

   def test_subfunc_func_1_retval( self ):
       only_retval = self._assert_sub_functionality( subfunc_func_1_retval, <args>, <kwargs> )

       <checks based on retval not being None>

但是对于具有多个返回值的测试函数,这不起作用(引发错误,因为在测试函数预期多次的情况下仅给出1次返回)。所以我们就这样做了:

def test_subfunc_func_2_retvals( self ):
    if not self._issupported:
        # 'Fail' case, where an error is expected
        retval1, retval2 = None
        _ = self._assert_sub_functionality( subfunc_func_2_retvals, <args>, <kwargs> )
    else:
        # Pass-case, no error expected. This works fine.
        retval1, retval2 = self._assert_sub_functionality( subfunc_func_2_retvals, <args>, <kwargs> )

    <checks based on the retvals not being None>

对self._issupported支持的额外检查是一种丑陋的恕我直言。

这可以用不同的方式完成吗?

_assert_sub_functionality可以确定一个函数有多少个返回值,并且在不支持子功能的情况下多次返回None?

TIA

2 个答案:

答案 0 :(得分:4)

首先,函数只有一个返回值,但是it could be a tuple

所以,你的问题是,你能否静态分析一个Python函数并推断它只返回特定元组,即那些具有一定大小的元组。

不幸的是,答案是否定的 - 很容易证明这会解决Halting Problem

答案 1 :(得分:0)

看看Ami Tavory和David Ehrmann给出的答案(以及Halting Problem wiki-page ;-))我得到了以下解决方案:

def _assert_sub_functionality( self, func, *args, **kwargs ):
    supported = self._issupported
    retval = None

    if not supported:
        self.assert_raises( <expected error>, func, *args, **kwargs )
    else:
        # retval will be filled with either 1 value or a tuple by
        # successful call.
        retval = func( *args, **kwargs )

    return supported, retval

def test_subfunc_func_1_retval( self ):
   retval = self._assert_sub_functionality( subfunc_func_1_retval, <args>, <kwargs> )

   issupported = retval[0]
   if issupported:
      real_retval = retval[1]
      <tests with real_retval>

def test_subfunc_func_2_retvals( self ):
    retval = self._assert_sub_functionality( subfunc_func_2_retvals, <args>, <kwargs> )

    issupported = retval[0]
    if issupported:
        (real_retval1, real_retval2) = retval[1]
            <checks with the real_retvals>

对两者都赞不绝口。 (解决方案检查也应该在David的评论之前;-))。