[Python] 파이썬 함수가 예외를 throw하는 것을 어떻게 테스트합니까?


Answers

unittest 모듈에서 TestCase.assertRaises (또는 TestCase.failUnlessRaises )를 사용하십시오. 예를 들면 다음과 같습니다.

import mymod

class MyTestCase(unittest.TestCase):
    def test1(self):
        self.assertRaises(SomeCoolException, mymod.myfunc)
Question

함수가 예상 된 예외를 throw하지 않는 경우에만 실패하는 unittest를 작성하는 방법은 무엇입니까?




나는 거의 모든 곳에서 doctest를 사용한다. 왜냐하면 내가 동시에 문서를 작성하고 테스트하는 것을 좋아하기 때문이다.

다음 코드를 살펴보십시오.

def throw_up(something, gowrong=False):
    """
    >>> throw_up('Fish n Chips')
    Traceback (most recent call last):
    ...
    Exception: Fish n Chips

    >>> throw_up('Fish n Chips', gowrong=True)
    'I feel fine!'
    """
    if gowrong:
        return "I feel fine!"
    raise Exception(something)

if __name__ == '__main__':
    import doctest
    doctest.testmod()

이 예제를 모듈에 넣고 명령 행에서 실행하면 두 테스트 케이스가 모두 평가되고 점검됩니다.

[1] Python 문서 : 23.2 doctest - 대화식 Python 예제 테스트




자신 만의 contextmanager 를 구축하여 예외가 발생했는지 확인할 수 있습니다.

import contextlib

@contextlib.contextmanager
def raises(exception):
    try:
        yield 
    except exception as e:
        assert True
    else:
        assert False

그리고 다음과 같이 raises 를 사용할 수 있습니다.

with raises(Exception):
    print "Hola"  # Calls assert False

with raises(Exception):
    raise Exception  # Calls assert True

pytest 를 사용하고 pytest , 이미 구현되어 있습니다. pytest.raises(Exception) 할 수 있습니다.

예:

def test_div_zero():
    with pytest.raises(ZeroDivisionError):
        1/0

결과 :

pigueiras@pigueiras$ py.test
================= test session starts =================
platform linux2 -- Python 2.6.6 -- py-1.4.20 -- pytest-2.5.2 -- /usr/bin/python
collected 1 items 

tests/test_div_zero.py:6: test_div_zero PASSED



unittest 모듈의 assertRaises 메소드를 살펴보십시오.




from : http://www.lengrand.fr/2011/12/pythonunittest-assertraises-raises-error/

먼저 dum_function.py 파일에있는 해당하는 (still dum : p) 함수가 있습니다.

def square_value(a):
   """
   Returns the square value of a.
   """
   try:
       out = a*a
   except TypeError:
       raise TypeError("Input should be a string:")

   return out

수행 할 테스트는 다음과 같습니다 (이 테스트 만 삽입 됨).

import dum_function as df # import function module
import unittest
class Test(unittest.TestCase):
   """
      The class inherits from unittest
      """
   def setUp(self):
       """
       This method is called before each test
       """
       self.false_int = "A"

   def tearDown(self):
       """
       This method is called after each test
       """
       pass
      #---
         ## TESTS
   def test_square_value(self):
       # assertRaises(excClass, callableObj) prototype
       self.assertRaises(TypeError, df.square_value(self.false_int))

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

우리는 이제 우리의 기능을 시험 할 준비가되었습니다! 테스트를 실행하려고 할 때 발생하는 상황은 다음과 같습니다.

======================================================================
ERROR: test_square_value (__main__.Test)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "test_dum_function.py", line 22, in test_square_value
    self.assertRaises(TypeError, df.square_value(self.false_int))
  File "/home/jlengrand/Desktop/function.py", line 8, in square_value
    raise TypeError("Input should be a string:")
TypeError: Input should be a string:

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

FAILED (errors=1)

TypeError가 발생하여 테스트 실패가 발생합니다. 문제는 이것이 우리가 원하는 행동과 정확히 일치한다는 것입니다.

이 오류를 피하려면 테스트 호출에서 lambda를 사용하여 함수를 실행하기 만하면됩니다.

self.assertRaises(TypeError, lambda: df.square_value(self.false_int))

최종 출력 :

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

OK

완벽 해!

... 나를 위해서도 완벽합니다 !!

Thansk a lot Julien Lengrand-Lambert




파이썬 함수가 예외를 throw하는 것을 어떻게 테스트합니까?

함수가 예상 된 예외를 throw하지 않는 경우에만 실패하는 테스트를 작성하는 방법은 무엇입니까?

짧은 답변:

컨텍스트 관리자로 self.assertRaises 메서드를 사용하십시오.

    def test_1_cannot_add_int_and_str(self):
        with self.assertRaises(TypeError):
            1 + '1'

데모

모범 사례 접근법은 Python 셸에서 매우 쉽게 보여줍니다.

unittest 라이브러리

파이썬 2.7 또는 3 :

import unittest

Python 2.6에서는 unittest 라는 2.7의 unittest 라이브러리의 백 포트를 설치할 수 있으며 unittest 로 별칭을 지정할 수 있습니다.

import unittest2 as unittest

예제 테스트

이제 Python 셸에 다음 Python 유형 안전 테스트를 붙여 넣으십시오.

class MyTestCase(unittest.TestCase):
    def test_1_cannot_add_int_and_str(self):
        with self.assertRaises(TypeError):
            1 + '1'
    def test_2_cannot_add_int_and_str(self):
        import operator
        self.assertRaises(TypeError, operator.add, 1, '1')

테스트는 컨텍스트 관리자로 assertRaises 를 사용합니다.이 컨텍스트 관리자는 기록되는 동안 오류가 제대로 캐치되고 정리되도록합니다.

컨텍스트 관리자 없이 테스트를 작성할 수도 있습니다 (테스트 2 참조). 첫 번째 인수는 올릴 오류 유형, 두 번째 인수, 테스트중인 함수, 나머지 args 및 키워드 args는 해당 함수에 전달됩니다.

컨텍스트 관리자를 사용하는 것이 훨씬 간단하고 읽기 쉽고 유지 관리가 가능하다고 생각합니다.

테스트 실행하기

테스트를 실행하려면 다음과 같이하십시오.

unittest.main(exit=False)

파이썬 2.6에서는 다음과 같은 것들이 필요할 것이다.

unittest.TextTestRunner().run(unittest.TestLoader().loadTestsFromTestCase(MyTestCase))

그리고 터미널은 다음을 출력해야합니다 :

..
----------------------------------------------------------------------
Ran 2 tests in 0.007s

OK
<unittest2.runner.TextTestResult run=2 errors=0 failures=0>

그리고 우리가 예상 한대로 TypeError 1'1' 을 추가하려고 시도합니다.

좀 더 자세한 결과를 얻으려면 다음을 시도하십시오.

unittest.TextTestRunner(verbosity=2).run(unittest.TestLoader().loadTestsFromTestCase(MyTestCase))



Python 2.7 이후 컨텍스트 관리자를 사용하여 실제 Exception 객체를 가져올 수 있습니다.

import unittest

def broken_function():
    raise Exception('This is broken')

class MyTestCase(unittest.TestCase):
    def test(self):
        with self.assertRaises(Exception) as context:
            broken_function()

        self.assertTrue('This is broken' in context.exception)

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

http://docs.python.org/dev/library/unittest.html#unittest.TestCase.assertRaises

파이썬 3.5 에서는 str 에서 context.exception 을 래핑해야합니다. 그렇지 않으면 TypeError

self.assertTrue('This is broken' in str(context.exception))



코드는이 패턴을 따라야합니다 (이것은 unittest 모듈 스타일 테스트입니다).

def test_afunction_throws_exception(self):
    try:
        afunction()
    except ExpectedException:
        pass
    except Exception as e:
       self.fail('Unexpected exception raised:', e)
    else:
       self.fail('ExpectedException not raised')

Python <2.7에서이 구문은 예상되는 예외의 특정 값을 검사 할 때 유용합니다. unittest 함수 assertRaises 는 예외가 발생했는지 검사합니다.




unittest 모듈에서 assertRaises를 사용할 수 있습니다.

import unittest

class TestClass():
  def raises_exception(self):
    raise Exception("test")

class MyTestCase(unittest.TestCase):
  def test_if_method_raises_correct_exception(self):
    test_class = TestClass()
    # note that you dont use () when passing the method to assertRaises
    self.assertRaises(Exception, test_class.raises_exception)



이전 답변의 코드는 다음과 같이 단순화 할 수 있습니다.

def test_afunction_throws_exception(self):
    self.assertRaises(ExpectedException, afunction)

그리고 함수가 인수를 취하는 경우, 다음과 같이 assertRaises에 인수를 전달하십시오.

def test_afunction_throws_exception(self):
    self.assertRaises(ExpectedException, afunction, arg1, arg2)



방금 Mock 라이브러리 가 assertRaisesWithMessage () 메서드 (unittest.TestCase 하위 클래스에 있음)를 제공한다는 것을 발견했습니다.이 메서드는 예상되는 예외가 발생했는지 확인하고 예상되는 메시지와 함께 발생하는지 확인합니다.

from testcase import TestCase

import mymod

class MyTestCase(TestCase):
    def test1(self):
        self.assertRaisesWithMessage(SomeCoolException,
                                     'expected message',
                                     mymod.myfunc)