urllib와 같은 mock / stub 파이썬 모듈은 어떻게 할 수 있습니까?
urllib.urlopen을 사용하여 외부 서버에서 페이지를 쿼리해야하는 함수를 테스트해야합니다 (urllib.urlencode도 사용함). 서버가 다운되고 페이지가 변경 될 수 있습니다. 나는 그것을 시험에 의존 할 수 없다.
urllib.urlopen이 반환하는 것을 제어하는 가장 좋은 방법은 무엇입니까?
또 다른 간단한 방법은 테스트가 urllib의 urlopen()
기능을 재정의하도록하는 것 입니다. 예를 들어, 모듈에
import urllib
def some_function_that_uses_urllib():
...
urllib.urlopen()
...
다음과 같이 테스트를 정의 할 수 있습니다.
import mymodule
def dummy_urlopen(url):
...
mymodule.urllib.urlopen = dummy_urlopen
당신의 테스트에서 함수를 호출 할 때 그런 다음 mymodule
, dummy_urlopen()
대신 실제의 호출됩니다 urlopen()
. Python과 같은 동적 언어를 사용하면 테스트를위한 메서드와 클래스를 매우 쉽게 스텁 아웃 할 수 있습니다.
테스트를 위해 종속성을 제거하는 방법에 대한 자세한 내용은 http://softwarecorner.wordpress.com/ 에서 내 블로그 게시물을 참조하십시오 .
내가 사용하고 모의의 패치 장식을 :
from mock import patch
[...]
@patch('urllib.urlopen')
def test_foo(self, urlopen_mock):
urlopen_mock.return_value = MyUrlOpenMock()
목스를 보셨나요 ? 필요한 모든 작업을 수행해야합니다. 다음은 필요한 솔루션을 보여주는 간단한 대화식 세션입니다.
>>> import urllib
>>> # check that it works
>>> urllib.urlopen('http://www.google.com/')
<addinfourl at 3082723820L ...>
>>> # check what happens when it doesn't
>>> urllib.urlopen('http://hopefully.doesnotexist.com/')
#-- snip --
IOError: [Errno socket error] (-2, 'Name or service not known')
>>> # OK, let's mock it up
>>> import mox
>>> m = mox.Mox()
>>> m.StubOutWithMock(urllib, 'urlopen')
>>> # We can be verbose if we want to :)
>>> urllib.urlopen(mox.IgnoreArg()).AndRaise(
... IOError('socket error', (-2, 'Name or service not known')))
>>> # Let's check if it works
>>> m.ReplayAll()
>>> urllib.urlopen('http://www.google.com/')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/lib/python2.5/site-packages/mox.py", line 568, in __call__
raise expected_method._exception
IOError: [Errno socket error] (-2, 'Name or service not known')
>>> # yay! now unset everything
>>> m.UnsetStubs()
>>> m.VerifyAll()
>>> # and check that it still works
>>> urllib.urlopen('http://www.google.com/')
<addinfourl at 3076773548L ...>
HTTPretty 는 FakeWeb 과 똑같은 방식으로 작동합니다. HTTPretty는 소켓 계층에서 작동하므로 모든 Python http 클라이언트 라이브러리를 가로 채서 작동해야합니다. urllib2, httplib2 및 요청에 대해 테스트되었습니다.
import urllib2
from httpretty import HTTPretty, httprettified
@httprettified
def test_one():
HTTPretty.register_uri(HTTPretty.GET, "http://yipit.com/",
body="Find the best daily deals")
fd = urllib2.urlopen('http://yipit.com')
got = fd.read()
fd.close()
assert got == "Find the best daily deals"
아마도이를 처리하는 가장 좋은 방법은 코드를 분할하여 페이지 콘텐츠를 처리하는 논리가 페이지를 가져 오는 코드에서 분할되도록하는 것입니다.
그런 다음 페처 코드의 인스턴스를 처리 로직에 전달하면 단위 테스트를위한 모의 페 처로 쉽게 대체 할 수 있습니다.
예 :
class Processor(oject):
def __init__(self, fetcher):
self.m_fetcher = fetcher
def doProcessing(self):
## use self.m_fetcher to get page contents
class RealFetcher(object):
def fetchPage(self, url):
## get real contents
class FakeFetcher(object):
def fetchPage(self, url):
## Return whatever fake contents are required for this test
모듈을로드하고 싶지 않은 경우 :
import sys,types
class MockCallable():
""" Mocks a function, can be enquired on how many calls it received """
def __init__(self, result):
self.result = result
self._calls = []
def __call__(self, *arguments):
"""Mock callable"""
self._calls.append(arguments)
return self.result
def called(self):
"""docstring for called"""
return self._calls
class StubModule(types.ModuleType, object):
""" Uses a stub instead of loading libraries """
def __init__(self, moduleName):
self.__name__ = moduleName
sys.modules[moduleName] = self
def __repr__(self):
name = self.__name__
mocks = ', '.join(set(dir(self)) - set(['__name__']))
return "<StubModule: %(name)s; mocks: %(mocks)s>" % locals()
class StubObject(object):
pass
그리고:
>>> urllib = StubModule("urllib")
>>> import urllib # won't actually load urllib
>>> urls.urlopen = MockCallable(StubObject())
>>> example = urllib.urlopen('http://example.com')
>>> example.read = MockCallable('foo')
>>> print(example.read())
'foo'
The simplest way is to change your function so that it doesn't necessarily use urllib.urlopen. Let's say this is your original function:
def my_grabber(arg1, arg2, arg3):
# .. do some stuff ..
url = make_url_somehow()
data = urllib.urlopen(url)
# .. do something with data ..
return answer
Add an argument which is the function to use to open the URL. Then you can provide a mock function to do whatever you need:
def my_grabber(arg1, arg2, arg3, urlopen=urllib.urlopen):
# .. do some stuff ..
url = make_url_somehow()
data = urlopen(url)
# .. do something with data ..
return answer
def test_my_grabber():
my_grabber(arg1, arg2, arg3, urlopen=my_mock_open)
Adding onto Clint Miller's answer, to do this I had to create a fake class that implements a read method like this:
class FakeURL:
def read(foo):
return '{"some":"json_text"}'
Then to stub out urllib2.open:
# Stub out urllib2.open.
def dummy_urlopen(foo, bar, baz):
return FakeURL()
urllib2.urlopen = dummy_urlopen
참고URL : https://stackoverflow.com/questions/295438/how-can-one-mock-stub-python-module-like-urllib
'Programing' 카테고리의 다른 글
HTML 및 CSS가있는 진행률 표시 줄 (0) | 2020.11.16 |
---|---|
탐색 창 헤더에서 TextView의 텍스트를 변경하는 방법은 무엇입니까? (0) | 2020.11.16 |
UISearchDisplayController가 탐색 모음을 숨기지 못하도록 방지 (0) | 2020.11.16 |
vim regex는 여러 연속 공백을 하나의 공백으로 만 바꿉니다. (0) | 2020.11.16 |
jQuery UI datepicker에서 오늘 날짜를 기본 날짜로 설정 (0) | 2020.11.16 |