Подтвердить что ты не робот

Как использовать pytest, чтобы проверить, что ошибка НЕ ​​поднята

Предположим, что мы имеем что-то вроде этого:

import py, pytest

ERROR1 = ' --- Error : value < 5! ---'
ERROR2 = ' --- Error : value > 10! ---'

class MyError(Exception):
    def __init__(self, m):
        self.m = m

    def __str__(self):
        return self.m

def foo(i):
    if i < 5:
        raise MyError(ERROR1)
    elif i > 10:
        raise MyError(ERROR2)
    return i


# ---------------------- TESTS -------------------------
def test_foo1():
    with pytest.raises(MyError) as e:
        foo(3)
    assert ERROR1 in str(e)

def test_foo2():
    with pytest.raises(MyError) as e:
        foo(11)
    assert ERROR2 in str(e)

def test_foo3():
        ....
        foo(7)
         ....

В: Как я могу сделать test_foo3() для проверки, что не вызвано MyError? Очевидно, что я мог просто проверить:

def test_foo3():
    assert foo(7) == 7

но я хочу проверить это через pytest.raises(). Возможно ли это? Например: в случае, эта функция "foo" вообще не имеет возвращаемого значения,

def foo(i):
    if i < 5:
        raise MyError(ERROR1)
    elif i > 10:
        raise MyError(ERROR2)

это может иметь смысл протестировать этот путь, imho.

4b9b3361

Ответ 1

Тест будет терпеть неудачу, если он вызывает любое неожиданное исключение. Вы можете просто вызвать foo (7), и вы испытаете, что MyError не будет поднят. Итак, следующего достаточно:

def test_foo3():
    foo(7)

Если вы действительно хотите написать инструкцию assert для этого, вы можете попробовать:

def test_foo3():
    try:
        foo(7)
    except MyError:
        pytest.fail("Unexpected MyError ..")

Ответ 2

Мне было любопытно узнать, будет ли работать not_raises. Быстрый тест этого (Test_notraises.py):

from contextlib import contextmanager

@contextmanager
def not_raises(ExpectedException):
    try:
        yield

    except ExpectedException, err:
        raise AssertionError(
            "Did raise exception {0} when it should not!".format(
                repr(ExpectedException)
            )
        )

    except Exception, err:
        raise AssertionError(
            "An unexpected exception {0} raised.".format(repr(err))
        )

def good_func():
    print "hello"


def bad_func():
    raise ValueError("BOOM!")


def ugly_func():
    raise IndexError("UNEXPECTED BOOM!")


def test_ok():
    with not_raises(ValueError):
        good_func()


def test_bad():
    with not_raises(ValueError):
        bad_func()


def test_ugly():
    with not_raises(ValueError):
        ugly_func()

Кажется, он работает. Однако я не уверен, действительно ли он хорошо читается в тест.

Ответ 3

Основываясь на том, что упоминал Ойсин.

Вы можете сделать простую функцию not_raises, которая действует аналогично pytest raises:

from contextlib import contextmanager

@contextmanager
def not_raises(exception):
  try:
    yield
  except exception:
    raise pytest.fail("DID RAISE {0}".format(exception))

Это хорошо, если вы хотите придерживаться того, что raises имеет аналог, и, следовательно, ваши тесты становятся более читабельными. В сущности, однако, вам действительно не нужно ничего, кроме просто запустить блок кода, который вы хотите протестировать на своей собственной линии - pytest все равно сбой, как только этот блок вызывает ошибку.