web-dev-qa-db-ja.com

pytestを使用してエラーが発生しないことを確認する方法

そのようなsmthがあると仮定しましょう:

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)
         ....

Q:どうすれば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)

このようにテストするのは理にかなっていると思います。

44
paraklet

予期しない例外が発生した場合、テストは失敗します。 foo(7)を呼び出すだけで、MyErrorが発生しないことをテストできます。したがって、以下で十分です。

def test_foo3():
    foo(7)

明示的になり、このためにアサートステートメントを記述したい場合は、次のことができます。

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

オイシンが述べたことの上に構築.

Pytestのraisesと同様に機能する簡単なnot_raises関数を作成できます。

from contextlib import contextmanager

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

これは、対応するraisesを持ち続けてテストを読みやすくしたい場合に適しています。ただし、本質的には、テストするコードのブロックを独自の行で実行する以外に、実際には何も必要ありません。pytestは、そのブロックでエラーが発生するとすぐに失敗します。

12
Pithikos

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()

うまくいくようです。しかし、テストで本当にうまく読めるかどうかはわかりません。

6
Oisin