unittest получил None от итератора вместо повышенной ошибки - PullRequest
0 голосов
/ 03 июня 2019

Я все еще изучаю unittest и поэтому не могу определить, что-то не хватает в моем тестовом примере в test_iterators.py ниже. Может кто-нибудь помочь мне понять, почему ValueError не удалось вызвать в unittest? Вот сценарии:

iterators.py

"""
Simple class to count from zero to N
"""
class count_to(object):
    def __init__(self, nber):
        self.nber = nber

    def __iter__(self):
        return count_to_iter(self.nber)


class count_to_iter(object):
    def __init__(self, nber):
        self.stopat = nber
        self.current_nber = 0

    def __next__(self):
        if self.stopat < 0:
            raise ValueError
        elif self.current_nber > self.stopat:
            raise StopIteration

        self.current_nber += 1

        return self.current_nber - 1


if __name__ == '__main__':
    for x in count_to(-1):
        print(x)

Тесты / test_iterators.py

import unittest
import iterators

class TestBaseIterators(unittest.TestCase):
    def setUp(self):
        pass

    # Can't get the negative test right yet. It returns None instead of raising a ValueError
    # Calling iterators.py directly and execute main successfully raised a ValueError however
    def test_negative(self):
        with self.assertRaises(ValueError): iterators.count_to(-1)


if __name__ == '__main__':
    unittest.main()

Я использовал аналогичный подход для проверки ранее возникших ошибок, и это сработало Однако для этого конкретного теста вот что я получаю из теста.

test_negative (test_iterators.TestBaseIterators) ... FAIL
NoneType: None

======================================================================
FAIL: test_negative (test_iterators.TestBaseIterators)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/Users/kerwei/Git/Concepts/tests/test_iterators.py", line 19, in test_negative
    with self.assertRaises(ValueError): iterators.count_to(-1)
AssertionError: ValueError not raised

----------------------------------------------------------------------
Ran 1 test in 0.004s

FAILED (failures=1)

Если бы я вызывал итераторы напрямую из __main__, я мог бы успешно получить ValueError .

(py36) Kers-MacBook-Air:Concepts kerwei$ python iterators.py
Traceback (most recent call last):
  File "iterators.py", line 29, in <module>
    for x in count_to(-1):
  File "iterators.py", line 19, in __next__
    raise ValueError
ValueError

1 Ответ

0 голосов
/ 03 июня 2019

count_to(-1) создает новый экземпляр count_to, он не проходит по нему, но вы поместили тест на значение self.stop_at и повысили ValueError в методе count_to_iter.__next__, так что вы, очевидно, не получите Ошибка ValueError, пока вы не выполните итерацию для экземпляра count_to.

Наивным решением было бы форсировать итерацию, то есть:

def test_negative(self):
    with self.assertRaises(ValueError): 
        # passing the iterable to `list` will force iteration
        list(iterators.count_to(-1))

Но корневая проблема на самом деле является скорее проблемой проектирования: поднятие ValueError в этой точке далеко от оптимального, поскольку это произойдет только при фактическом использовании итерируемого, поэтому вам придется проверять стек вызовов до тех пор, пока вы не найдете, где count_to было передано неправильное значение. Гораздо лучшим решением является проверка значения и, в конечном итоге, его повышение непосредственно в точке, где создается экземпляр count_to, поэтому он всегда и сразу прерывается (вместо «в конце концов, когда вы пытаетесь использовать итератор в некоторой, возможно, удаленной части кода) :

class count_to(object):
    def __init__(self, nber):
        if nber < 0:
            raise ValueError("count_to argument must be a positive integer")
        self.nber = nber

    def __iter__(self):
        return count_to_iter(self.nber)

И тогда ваш текущий тестовый код будет работать так, как задумано.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...