소개
Python 의 동적인 특성으로 인해 대부분의 애플리케이션에서 테스팅은 매우 중요합니다. 버그를 찾아주는 컴파일러가 없기 때문입니다. 버그를 찾는 유일한 방법은 코드를 실행하고 모든 기능을 시도해 보는 것입니다.
This tutorial is from open-source community. Access the source code
Python 의 동적인 특성으로 인해 대부분의 애플리케이션에서 테스팅은 매우 중요합니다. 버그를 찾아주는 컴파일러가 없기 때문입니다. 버그를 찾는 유일한 방법은 코드를 실행하고 모든 기능을 시도해 보는 것입니다.
assert 문은 프로그램의 내부 검사입니다. 표현식이 참이 아니면 AssertionError 예외를 발생시킵니다.
assert 문법:
assert <expression> [, 'Diagnostic message']
예를 들어:
assert isinstance(10, int), 'Expected int'
사용자 입력 (예: 웹 양식에 입력된 데이터 등) 을 확인하는 데 사용해서는 안 됩니다. 이는 내부 검사 및 불변성 (항상 참이어야 하는 조건) 을 위한 것입니다.
계약에 의한 설계 (Design By Contract) 라고도 알려진 어서션의 자유로운 사용은 소프트웨어 설계를 위한 접근 방식입니다. 이는 소프트웨어 설계자가 소프트웨어 구성 요소에 대한 정확한 인터페이스 사양을 정의해야 한다고 규정합니다.
예를 들어, 함수의 모든 입력에 어서션을 넣을 수 있습니다.
def add(x, y):
assert isinstance(x, int), 'Expected int'
assert isinstance(y, int), 'Expected int'
return x + y
입력을 확인하면 적절한 인수를 사용하지 않는 호출자를 즉시 잡아낼 수 있습니다.
>>> add(2, 3)
5
>>> add('2', '3')
Traceback (most recent call last):
...
AssertionError: Expected int
>>>
어서션은 간단한 테스트에도 사용할 수 있습니다.
def add(x, y):
return x + y
assert add(2,2) == 4
이러한 방식으로 코드가 있는 동일한 모듈에 테스트를 포함시킬 수 있습니다.
장점: 코드가 명백하게 손상된 경우, 모듈을 가져오려는 시도는 충돌을 일으킬 것입니다.
이는 철저한 테스트에는 권장되지 않습니다. 이는 기본적인 "스모크 테스트 (smoke test)"에 가깝습니다. 함수가 어떤 예시에서라도 작동합니까? 그렇지 않다면, 무언가 확실히 잘못된 것입니다.
unittest 모듈simple.py에 코드가 있다고 가정해 보겠습니다.
## simple.py
def add(x, y):
return x + y
이제, 이를 테스트하고 싶다고 가정해 보겠습니다. /home/labex/project/test_simple.py와 같이 별도의 테스트 파일을 만듭니다.
## test_simple.py
import simple
import unittest
그런 다음 테스트 클래스를 정의합니다.
## test_simple.py
import simple
import unittest
## Notice that it inherits from unittest.TestCase
class TestAdd(unittest.TestCase):
...
테스트 클래스는 unittest.TestCase를 상속받아야 합니다.
테스트 클래스에서 테스트 메서드를 정의합니다.
## test_simple.py
import simple
import unittest
## Notice that it inherits from unittest.TestCase
class TestAdd(unittest.TestCase):
def test_simple(self):
## Test with simple integer arguments
r = simple.add(2, 2)
self.assertEqual(r, 5)
def test_str(self):
## Test with strings
r = simple.add('hello', 'world')
self.assertEqual(r, 'helloworld')
*중요: 각 메서드는 test로 시작해야 합니다.
unittest 사용하기unittest에는 여러 가지 내장 어서션 (assertion) 이 있습니다. 각각은 서로 다른 것을 어서션합니다.
## Assert that expr is True
self.assertTrue(expr)
## Assert that x == y
self.assertEqual(x,y)
## Assert that x != y
self.assertNotEqual(x,y)
## Assert that x is near y
self.assertAlmostEqual(x,y,places)
## Assert that callable(arg1,arg2,...) raises exc
self.assertRaises(exc, callable, arg1, arg2, ...)
이것은 완전한 목록이 아닙니다. 모듈에는 다른 어서션도 있습니다.
unittest 실행하기테스트를 실행하려면 코드를 스크립트로 만듭니다.
## test_simple.py
...
if __name__ == '__main__':
unittest.main()
그런 다음 테스트 파일에서 Python 을 실행합니다.
$ python3 test_simple.py
F.
========================================================
FAIL: test_simple (__main__.TestAdd)
--------------------------------------------------------
Traceback (most recent call last):
File "testsimple.py", line 8, in test_simple
self.assertEqual(r, 5)
AssertionError: 4 != 5
--------------------------------------------------------
Ran 2 tests in 0.000s
FAILED (failures=1)
효과적인 유닛 테스트 (unit testing) 는 일종의 기술이며, 대규모 애플리케이션의 경우 상당히 복잡해질 수 있습니다.
unittest 모듈에는 테스트 러너 (test runner), 결과 수집 및 테스트의 다른 측면과 관련된 많은 옵션이 있습니다. 자세한 내용은 문서를 참조하십시오.
내장된 unittest 모듈은 어디에서나 사용할 수 있다는 장점이 있습니다. 즉, Python 의 일부입니다. 그러나 많은 프로그래머는 또한 이것이 상당히 장황하다고 생각합니다. 널리 사용되는 대안은 pytest입니다. pytest 를 사용하면 테스트 파일이 다음과 같이 단순화됩니다.
## test_simple.py
import simple
def test_simple():
assert simple.add(2,2) == 4
def test_str():
assert simple.add('hello','world') == 'helloworld'
테스트를 실행하려면 python -m pytest와 같은 명령을 입력하기만 하면 됩니다. 그러면 모든 테스트를 찾아 실행합니다. 이 모듈은 pip install pytest를 사용하여 설치할 수 있습니다.
이 예제보다 pytest에는 훨씬 더 많은 기능이 있지만, 사용해보기로 결정했다면 일반적으로 시작하기가 매우 쉽습니다.
이 연습에서는 Python 의 unittest 모듈 사용의 기본 메커니즘을 탐구합니다.
이전 연습에서는 Stock 클래스를 포함하는 stock.py 파일을 작성했습니다. 이 연습에서는 유형 속성을 포함하는 Exercise 7.9 에 대해 작성된 코드를 사용한다고 가정합니다. 어떤 이유로 작동하지 않는 경우, Solutions/7_9에서 솔루션을 작업 디렉토리로 복사할 수 있습니다.
별도의 파일 test_stock.py에 Stock 클래스에 대한 일련의 유닛 테스트를 작성하십시오. 시작하기 위해 인스턴스 생성을 테스트하는 작은 코드 조각이 있습니다.
## test_stock.py
import unittest
import stock
class TestStock(unittest.TestCase):
def test_create(self):
s = stock.Stock('GOOG', 100, 490.1)
self.assertEqual(s.name, 'GOOG')
self.assertEqual(s.shares, 100)
self.assertEqual(s.price, 490.1)
if __name__ == '__main__':
unittest.main()
유닛 테스트를 실행하십시오. 다음과 같은 출력을 얻을 수 있습니다.
.
----------------------------------------------------------------------
Ran 1 tests in 0.000s
OK
작동하는지 확인했으면 다음을 확인하는 추가 유닛 테스트를 작성하십시오.
s.cost 속성이 올바른 값 (49010.0) 을 반환하는지 확인합니다.s.sell() 메서드가 올바르게 작동하는지 확인합니다. s.shares의 값을 적절하게 감소시켜야 합니다.s.shares 속성을 정수가 아닌 값으로 설정할 수 없는지 확인합니다.마지막 부분의 경우 예외가 발생했는지 확인해야 합니다. 이를 수행하는 쉬운 방법은 다음과 같은 코드를 사용하는 것입니다.
class TestStock(unittest.TestCase):
...
def test_bad_shares(self):
s = stock.Stock('GOOG', 100, 490.1)
with self.assertRaises(TypeError):
s.shares = '100'
축하합니다! 테스트 랩을 완료했습니다. LabEx 에서 더 많은 랩을 연습하여 기술을 향상시킬 수 있습니다.