Python 은 유닛 테스트 에서 대상 에 게 패 치 를 어떻게 합 니까?

문제.
당신 이 쓴 단원 테스트 에 서 는 지정 한 대상 에 게 패 치 를 쳐 서 테스트 에서 의 기대 행 위 를 단언 해 야 합 니 다(예 를 들 어 호출 된 매개 변수 개수,지정 한 속성 에 접근 하 는 등).
해결 방안unittest.mock.patch() 함 수 는 이 문 제 를 해결 하 는 데 사용 할 수 있다.patch() 장식 기,컨 텍스트 관리자 또는 단독 사용 으로 도 사용 할 수 있 습 니 다.흔 하지 않 지만.예 를 들 어 다음은 장식 기로 사용 하 는 예 입 니 다.

from unittest.mock import patch
import example

@patch('example.func')
def test1(x, mock_func):
  example.func(x)    # Uses patched example.func
  mock_func.assert_called_with(x)
컨 텍스트 관리자 로 도 사용 할 수 있 습 니 다.

with patch('example.func') as mock_func:
  example.func(x)   # Uses patched example.func
  mock_func.assert_called_with(x)
마지막 으로 패 치 를 수 동 으로 사용 할 수 있 습 니 다.

p = patch('example.func')
mock_func = p.start()
example.func(x)
mock_func.assert_called_with(x)
p.stop()
가능 하 다 면 장식 기와 컨 텍스트 관리 자 를 겹 쳐 여러 대상 에 게 패 치 를 할 수 있 습 니 다.예 를 들 면:

@patch('example.func1')
@patch('example.func2')
@patch('example.func3')
def test1(mock1, mock2, mock3):
  ...

def test2():
  with patch('example.patch1') as mock1, \
     patch('example.patch2') as mock2, \
     patch('example.patch3') as mock3:
  ...
토론 하 다.patch() 존재 하 는 대상 의 전체 경로 이름 을 받 아들 여 새로운 값 으로 바 꿉 니 다.원래 값 은 장식 기 함수 나 컨 텍스트 관리자 가 완 료 된 후에 자동 으로 회 복 됩 니 다.기본적으로 모든 값 은MagicMock인 스 턴 스 로 대 체 됩 니 다.예 를 들 면:

>>> x = 42
>>> with patch('__main__.x'):
...   print(x)
...
<MagicMock name='x' id='4314230032'>
>>> x
42
>>>
단,patch() 에 두 번 째 인 자 를 제공 함으로써 원 하 는 것 으로 값 을 바 꿀 수 있 습 니 다.

>>> x
42
>>> with patch('__main__.x', 'patched_value'):
...   print(x)
...
patched_value
>>> x
42
>>>
교체 값 으로 사 용 된MagicMock인 스 턴 스 는 호출 가능 한 대상 과 인 스 턴 스 를 모 의 할 수 있 습 니 다.그들 은 대상 의 사용 정 보 를 기록 하고 단언 검 사 를 허용 합 니 다.예 를 들 어:

>>> from unittest.mock import MagicMock
>>> m = MagicMock(return_value = 10)
>>> m(1, 2, debug=True)
10
>>> m.assert_called_with(1, 2, debug=True)
>>> m.assert_called_with(1, 2)
Traceback (most recent call last):
 File "<stdin>", line 1, in <module>
 File ".../unittest/mock.py", line 726, in assert_called_with
  raise AssertionError(msg)
AssertionError: Expected call: mock(1, 2)
Actual call: mock(1, 2, debug=True)
>>>

>>> m.upper.return_value = 'HELLO'
>>> m.upper('hello')
'HELLO'
>>> assert m.upper.called

>>> m.split.return_value = ['hello', 'world']
>>> m.split('hello world')
['hello', 'world']
>>> m.split.assert_called_with('hello world')
>>>

>>> m['blah']
<MagicMock name='mock.__getitem__()' id='4314412048'>
>>> m.__getitem__.called
True
>>> m.__getitem__.assert_called_with('blah')
>>>
일반적으로 이 조작 들 은 한 단원 테스트 에서 이 루어 진다.예 를 들 어 아래 와 같은 함수 가 있다 고 가정 합 니 다.

# example.py
from urllib.request import urlopen
import csv

def dowprices():
  u = urlopen('http://finance.yahoo.com/d/quotes.csv?s=@^DJI&f=sl1')
  lines = (line.decode('utf-8') for line in u)
  rows = (row for row in csv.reader(lines) if len(row) == 2)
  prices = { name:float(price) for name, price in rows }
  return prices
일반적으로 이 함 수 는 웹 에서 데 이 터 를 가 져 와 분석 합 니 다.유닛 테스트 에서 미리 정 의 된 데이터 세트 를 줄 수 있 습 니 다.다음은 패 치 작업 의 예 입 니 다.

import unittest
from unittest.mock import patch
import io
import example

sample_data = io.BytesIO(b'''\
"IBM",91.1\r
"AA",13.25\r
"MSFT",27.72\r
\r
''')

class Tests(unittest.TestCase):
  @patch('example.urlopen', return_value=sample_data)
  def test_dowprices(self, mock_urlopen):
    p = example.dowprices()
    self.assertTrue(mock_urlopen.called)
    self.assertEqual(p,
             {'IBM': 91.1,
             'AA': 13.25,
             'MSFT' : 27.72})

if __name__ == '__main__':
  unittest.main()
이 예 에서urlopen() 모듈 에 있 는example함수 가 아 날로 그 대상 으로 대체 되 고 이 대상 은 테스트 데 이 터 를 포함 한urlopen() 을 되 돌려 줍 니 다.
또 하 나 는 패 치 를 할 때 우 리 는ByteIO()대신example.urlopen 을 사용 했다.패 치 를 만 들 때 테스트 코드 에 있 는 이름 을 사용 해 야 합 니 다.테스트 코드 가 사용urllib.request.urlopen 되 었 기 때문에from urllib.request import urlopen 함수 에서 사용 하 는dowprices() 함 수 는 실제urlopen() 모듈 에 있 습 니 다.
이 절 은 사실상example모듈 에 대한 수박 겉 핥 기 일 뿐이다.더 많은 고 급 스 러 운 특성 을 참고 하 시기 바 랍 니 다공식 문서
이상 은 파 이 썬 이 유닛 테스트 에서 대상 에 게 패 치 를 하 는 방법 에 대한 상세 한 내용 입 니 다.파 이 썬 유닛 테스트 에 관 한 자 료 는 우리 의 다른 관련 글 을 주목 하 세 요!

좋은 웹페이지 즐겨찾기