Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/296.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何在单个Python单元测试中处理多个断言?_Python_Unit Testing_Testing_Unittest2 - Fatal编程技术网

如何在单个Python单元测试中处理多个断言?

如何在单个Python单元测试中处理多个断言?,python,unit-testing,testing,unittest2,Python,Unit Testing,Testing,Unittest2,这是在执行具有多个独立故障模式的单个测试时出现的问题,因为有多个输出流。我还想展示在所有这些模式上断言数据的结果,不管哪种模式首先失败。Python的unittest除了使用一个套件来表示单个测试之外没有这样的特性,这是不可接受的,因为我的单个测试总是需要作为单个单元运行;它只是没有抓住事物的本质 一个实际的例子是测试一个也会生成日志的对象。您希望断言它的方法的输出,但也希望断言日志输出。这两个输出需要不同的测试,这些测试可以灵活地表示为两个库存断言表达式,但您也不希望其中一个的失败隐藏测试中另

这是在执行具有多个独立故障模式的单个测试时出现的问题,因为有多个输出流。我还想展示在所有这些模式上断言数据的结果,不管哪种模式首先失败。Python的unittest除了使用一个套件来表示单个测试之外没有这样的特性,这是不可接受的,因为我的单个测试总是需要作为单个单元运行;它只是没有抓住事物的本质


一个实际的例子是测试一个也会生成日志的对象。您希望断言它的方法的输出,但也希望断言日志输出。这两个输出需要不同的测试,这些测试可以灵活地表示为两个库存断言表达式,但您也不希望其中一个的失败隐藏测试中另一个的可能失败。所以你真的需要同时测试两者

我拼凑了这个有用的小部件来解决我的问题

def logFailures(fnList):
    failurelog = []
    for fn in fnList:
        try:
            fn()
        except AssertionError as e:
            failurelog.append("\nFailure %d: %s" % (len(failurelog)+1,str(e)))

    if len(failurelog) != 0:
        raise AssertionError(
            "%d failures within test.\n %s" % (len(failurelog),"\n".join(failurelog))
        )
其用法如下:

def test__myTest():
    # do some work here
    logFailures([
        lambda: assert_(False,"This test failed."),
        lambda: assert_(False,"This test also failed."),
    ])
结果是logFailures()将引发一个异常,该异常包含在列表中的方法中引发的所有断言的日志


问题:虽然这样做了,但我想知道是否有更好的方法来处理这个问题,除了创建嵌套的测试套件等等?

我不同意主流观点,即应该为每个断言编写一个测试方法。在某些情况下,您希望在一个测试方法中检查多个内容。以下是我如何做到这一点的答案:

# Works with unittest in Python 2.7
class ExpectingTestCase(unittest.TestCase):
    def run(self, result=None):
        self._result = result
        self._num_expectations = 0
        super(ExpectingTestCase, self).run(result)

    def _fail(self, failure):
        try:
            raise failure
        except failure.__class__:
            self._result.addFailure(self, sys.exc_info())

    def expect_true(self, a, msg):
        if not a:
            self._fail(self.failureException(msg))
        self._num_expectations += 1

    def expect_equal(self, a, b, msg=''):
        if a != b:
            msg = '({}) Expected {} to equal {}. '.format(self._num_expectations, a, b) + msg
            self._fail(self.failureException(msg))
        self._num_expectations += 1
以下是一些我认为有用且没有风险的情况:

1) 当您想要为不同的数据集测试代码时。这里我们有一个add()函数,我想用几个示例输入来测试它。为3个数据集编写3个测试方法意味着重复你自己,这是不好的。尤其是如果电话更详细的话

class MyTest(ExpectingTestCase):
    def test_multiple_inputs(self):
        for a, b, expect in ([1,1,2], [0,0,0], [2,2,4]):
            self.expect_equal(expect, add(a,b), 'inputs: {} {}'.format(a,b))
2) 当您想要检查一个函数的多个输出时。我想检查每个输出,但我不想第一次失败掩盖了其他两个

class MyTest(ExpectingTestCase):
    def test_things_with_no_side_effects(self):
        a, b, c = myfunc()
        self.expect_equal('first value', a)
        self.expect_equal('second value', b)
        self.expect_equal('third value', c)

3) 测试需要大量的安装成本。测试必须快速运行,否则人们将停止使用它们。有些测试需要一个数据库或网络连接,这需要一秒钟的时间,这会减慢测试速度。如果您正在测试db连接本身,那么您可能需要进行速度测试。但是如果您正在测试一些不相关的东西,我们希望对一整套检查执行一次缓慢的设置。

这对我来说感觉像是过度工程化了。要么:

  • 在一个测试用例中使用两个断言。如果第一个断言失败,则是真的,您将不知道第二个断言是否通过。但无论如何,您都要修复代码,所以请修复它,然后您将发现第二个断言是否通过

  • 编写两个测试,一个用于检查每个条件。如果您担心测试中出现重复的代码,请将大部分代码放在从测试中调用的helper方法中


使用子测试时,执行不会在第一次失败后停止

下面是两个失败断言的示例:

class TestMultipleAsserts(unittest.TestCase):

    def test_multipleasserts(self):
        with self.subTest():
            self.assertEqual(1, 0)
        with self.subTest():
            self.assertEqual(2, 0)
输出将是:

======================================================================
FAIL: test_multipleasserts (__main__.TestMultipleAsserts) (<subtest>)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "./test.py", line 9, in test_multipleasserts
    self.assertEqual(1, 0)
AssertionError: 1 != 0

======================================================================
FAIL: test_multipleasserts (__main__.TestMultipleAsserts) (<subtest>)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "./test.py", line 11, in test_multipleasserts
    self.assertEqual(2, 0)
AssertionError: 2 != 0

----------------------------------------------------------------------
Ran 1 test in 0.000s

FAILED (failures=2)

“您也不希望一方的失败在测试中隐藏另一方可能的失败”。如果你想测试两个不同的东西,那就做两个不同的测试吧!“您也不希望一方的失败在测试中隐藏另一方可能的失败”。是-我想要:这些是单元测试。如果一个测试失败,则更正失败并重新运行测试。默认情况下,单元测试框架中应该存在类似的内容。有人知道有这样的功能吗?需要注意的是,这只适用于Python3.4和更高版本,根据您的链接,这正好是我所需要的,而不是巧合。我希望询问者回来并接受这一点。
class MyTestCase(unittest.TestCase):
    def expectEqual(self, first, second, msg=None):
        with self.subTest():
            self.assertEqual(first, second, msg)

class TestMA(MyTestCase):
    def test_ma(self):
        self.expectEqual(3, 0)
        self.expectEqual(4, 0)