Python 3.x 不了解带生成器的assertRaises+;单元测试

Python 3.x 不了解带生成器的assertRaises+;单元测试,python-3.x,unit-testing,generator,raise,Python 3.x,Unit Testing,Generator,Raise,我不明白怎么了。这里有两个简单的范围生成器。两者都会使输入值误差大于最大值。第一个是生成器理解,第二个是使用收益率 MSG = 'Wrong number' MAX = 20 def test_compr(n, m=MAX): if n > m: raise ValueError('{} {} in {}'.format(MSG, n, test_compr.__name__)) return (i for i in range(n)) def test

我不明白怎么了。这里有两个简单的范围生成器。两者都会使输入值误差大于最大值。第一个是生成器理解,第二个是使用收益率

MSG = 'Wrong number'
MAX = 20

def test_compr(n, m=MAX):
    if n > m:
        raise ValueError('{} {} in {}'.format(MSG, n, test_compr.__name__))
    return (i for i in range(n))

def test_yield(n, m=MAX):
    if n > m:
        raise ValueError('{} {} in {}'.format(MSG, n, test_yield.__name__))
    i = 0
    while i < n:
        yield i
        i += 1

def main():
    n = 30

    try:
        print(list(test_compr(n)))
    except ValueError as e:
        print(e)

    try:
        print(list(test_yield(n)))
    except ValueError as e:
        print(e)


if __name__ == '__main__':
        main()
这正是我们想要的。 现在进行一些unittest测试,以确保实际引发ValueError

import unittest
from t import test_compr, test_yield

N_BIG = 30
N_OK = 19


# test generator comprehension
class TestCompr(unittest.TestCase):
    def test_ok(self):
        tst = N_OK
        g = test_compr(tst)
        for num in range(tst):
            self.assertEqual(num, next(g))

    def test_exception(self):
        TST = N_BIG
        with self.assertRaises(ValueError) as c:
            test_compr(N_BIG)

# test yield
class TestYield(unittest.TestCase):
    def test_ok(self):
        tst = N_OK
        g = test_yield(tst)
        for num in range(tst):
            self.assertEqual(num, next(g))

    def test_exception(self):
        tst=N_BIG
        with self.assertRaises(ValueError) as c:
            test_yield(tst)

if __name__ == '__main__':
    unittest.main()
使用生成器理解的测试会产生错误,但使用屈服的生成器不会。一旦我删除了yield,我就会看到unittest在assertRaises上生成正确的结果

试图安装最新的python。同样的问题

python3.8 --version && python3.8 tests.py
Python 3.8.0
..F.
======================================================================
FAIL: test_exception (__main__.TestYield)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "tests.py", line 31, in test_exception
    test_yield(tst)
AssertionError: ValueError not raised

----------------------------------------------------------------------
Ran 4 tests in 0.001s

FAILED (failures=1)

不确定是什么问题以及如何解决。我从python3.5上稍微复杂一点的代码开始,结果基本相同。制作上面的样板以在简单的代码上重现问题。

这种看似不一致的行为的原因如下:

  • test\u产量
    是一个发生器功能
  • test\u compr
    是一个返回生成器的函数
这意味着,当您调用
test\u compr
时,函数体将立即执行,并作为其结果返回一个生成器(或抛出)

相反,当您调用
test\u yield
时,您会收到一个生成器对象。生成器的执行不会在创建时开始,而是在第一次调用
next
函数时开始。因此,您的测试函数应该如下所示:

def test_exception(self):
    with self.assertRaises(ValueError) as c:
        g = test_yield(N_BIG)
        next(g)
python3.8 --version && python3.8 tests.py
Python 3.8.0
..F.
======================================================================
FAIL: test_exception (__main__.TestYield)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "tests.py", line 31, in test_exception
    test_yield(tst)
AssertionError: ValueError not raised

----------------------------------------------------------------------
Ran 4 tests in 0.001s

FAILED (failures=1)
def test_exception(self):
    with self.assertRaises(ValueError) as c:
        g = test_yield(N_BIG)
        next(g)