Commit 7c7a815d authored by J. Fernando Sánchez's avatar J. Fernando Sánchez
Browse files

Add *responses* to improve mocking

parent a3eb8f19
...@@ -13,7 +13,7 @@ class Client(object): ...@@ -13,7 +13,7 @@ class Client(object):
return self.request('/', method=method, input=input, **kwargs) return self.request('/', method=method, input=input, **kwargs)
def evaluate(self, input, method='GET', **kwargs): def evaluate(self, input, method='GET', **kwargs):
return self.request('/evaluate', method = method, input=input, **kwargs) return self.request('/evaluate', method=method, input=input, **kwargs)
def plugins(self, *args, **kwargs): def plugins(self, *args, **kwargs):
resp = self.request(path='/plugins').plugins resp = self.request(path='/plugins').plugins
...@@ -24,7 +24,7 @@ class Client(object): ...@@ -24,7 +24,7 @@ class Client(object):
return {d.name: d for d in resp} return {d.name: d for d in resp}
def request(self, path=None, method='GET', **params): def request(self, path=None, method='GET', **params):
url = '{}{}'.format(self.endpoint, path) url = '{}{}'.format(self.endpoint.rstrip('/'), path)
response = requests.request(method=method, url=url, params=params) response = requests.request(method=method, url=url, params=params)
try: try:
resp = models.from_dict(response.json()) resp = models.from_dict(response.json())
......
...@@ -24,6 +24,7 @@ import nltk ...@@ -24,6 +24,7 @@ import nltk
from .. import models, utils from .. import models, utils
from .. import api from .. import api
from .. import gsitk_compat from .. import gsitk_compat
from .. import testing
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
...@@ -143,14 +144,23 @@ class Plugin(with_metaclass(PluginMeta, models.Plugin)): ...@@ -143,14 +144,23 @@ class Plugin(with_metaclass(PluginMeta, models.Plugin)):
self.log.warn('Test case failed:\n{}'.format(pprint.pformat(case))) self.log.warn('Test case failed:\n{}'.format(pprint.pformat(case)))
raise raise
def test_case(self, case): def test_case(self, case, mock=testing.MOCK_REQUESTS):
entry = models.Entry(case['entry']) entry = models.Entry(case['entry'])
given_parameters = case.get('params', case.get('parameters', {})) given_parameters = case.get('params', case.get('parameters', {}))
expected = case.get('expected', None) expected = case.get('expected', None)
should_fail = case.get('should_fail', False) should_fail = case.get('should_fail', False)
responses = case.get('responses', [])
try: try:
params = api.parse_params(given_parameters, self.extra_params) params = api.parse_params(given_parameters, self.extra_params)
res = list(self.analyse_entries([entry, ], params))
method = partial(self.analyse_entries, [entry, ], params)
if mock:
res = list(method())
else:
with testing.patch_all_requests(responses):
res = list(method())
if not isinstance(expected, list): if not isinstance(expected, list):
expected = [expected] expected = [expected]
......
...@@ -4,6 +4,8 @@ import json ...@@ -4,6 +4,8 @@ import json
from senpy.plugins import SentimentPlugin from senpy.plugins import SentimentPlugin
from senpy.models import Sentiment from senpy.models import Sentiment
ENDPOINT = 'http://www.sentiment140.com/api/bulkClassifyJson'
class Sentiment140(SentimentPlugin): class Sentiment140(SentimentPlugin):
'''Connects to the sentiment140 free API: http://sentiment140.com''' '''Connects to the sentiment140 free API: http://sentiment140.com'''
...@@ -26,7 +28,7 @@ class Sentiment140(SentimentPlugin): ...@@ -26,7 +28,7 @@ class Sentiment140(SentimentPlugin):
def analyse_entry(self, entry, params): def analyse_entry(self, entry, params):
lang = params["language"] lang = params["language"]
res = requests.post("http://www.sentiment140.com/api/bulkClassifyJson", res = requests.post(ENDPOINT,
json.dumps({ json.dumps({
"language": lang, "language": lang,
"data": [{ "data": [{
...@@ -52,18 +54,6 @@ class Sentiment140(SentimentPlugin): ...@@ -52,18 +54,6 @@ class Sentiment140(SentimentPlugin):
entry.language = lang entry.language = lang
yield entry yield entry
def test(self, *args, **kwargs):
'''
To avoid calling the sentiment140 API, we will mock the results
from requests.
'''
from senpy.testing import patch_requests
expected = {"data": [{"polarity": 4}]}
with patch_requests(expected) as (request, response):
super(Sentiment140, self).test(*args, **kwargs)
assert request.called
assert response.json.called
test_cases = [ test_cases = [
{ {
'entry': { 'entry': {
...@@ -77,6 +67,9 @@ class Sentiment140(SentimentPlugin): ...@@ -77,6 +67,9 @@ class Sentiment140(SentimentPlugin):
'marl:hasPolarity': 'marl:Positive', 'marl:hasPolarity': 'marl:Positive',
} }
] ]
} },
'responses': [{'url': ENDPOINT,
'method': 'POST',
'json': {'data': [{'polarity': 4}]}}]
} }
] ]
try:
from unittest.mock import patch, MagicMock
except ImportError:
from mock import patch, MagicMock
from past.builtins import basestring from past.builtins import basestring
import os
import json import responses as requestmock
from contextlib import contextmanager
from .models import BaseModel from .models import BaseModel
@contextmanager MOCK_REQUESTS = os.environ.get('MOCK_REQUESTS', '').lower() in ['no', 'false']
def patch_requests(value, code=200):
success = MagicMock()
if isinstance(value, BaseModel):
value = value.jsonld()
if not isinstance(value, basestring):
data = json.dumps(value)
else:
data = value
success.json.return_value = value def patch_all_requests(responses):
success.status_code = code patched = requestmock.RequestsMock()
success.content = data
success.text = data
method_mocker = MagicMock() for response in responses or []:
method_mocker.return_value = success args = response.copy()
with patch.multiple('requests', request=method_mocker, if 'json' in args and isinstance(args['json'], BaseModel):
get=method_mocker, post=method_mocker): args['json'] = args['json'].jsonld()
yield method_mocker, success args['method'] = getattr(requestmock, args.get('method', 'GET'))
assert method_mocker.called patched.add(**args)
return patched
def patch_requests(url, response, method='GET', status=200):
args = {'url': url, 'method': method, 'status': status}
if isinstance(response, basestring):
args['body'] = response
else:
args['json'] = response
return patch_all_requests([args])
...@@ -14,22 +14,15 @@ class ModelsTest(TestCase): ...@@ -14,22 +14,15 @@ class ModelsTest(TestCase):
def test_client(self): def test_client(self):
endpoint = 'http://dummy/' endpoint = 'http://dummy/'
client = Client(endpoint) client = Client(endpoint)
with patch_requests(Results()) as (request, response): with patch_requests('http://dummy/', Results()):
resp = client.analyse('hello') resp = client.analyse('hello')
assert isinstance(resp, Results) assert isinstance(resp, Results)
request.assert_called_with( with patch_requests('http://dummy/', Error('Nothing')):
url=endpoint + '/', method='GET', params={'input': 'hello'})
with patch_requests(Error('Nothing')) as (request, response):
try: try:
client.analyse(input='hello', algorithm='NONEXISTENT') client.analyse(input='hello', algorithm='NONEXISTENT')
raise Exception('Exceptions should be raised. This is not golang') raise Exception('Exceptions should be raised. This is not golang')
except Error: except Error:
pass pass
request.assert_called_with(
url=endpoint + '/',
method='GET',
params={'input': 'hello',
'algorithm': 'NONEXISTENT'})
def test_plugins(self): def test_plugins(self):
endpoint = 'http://dummy/' endpoint = 'http://dummy/'
...@@ -37,11 +30,8 @@ class ModelsTest(TestCase): ...@@ -37,11 +30,8 @@ class ModelsTest(TestCase):
plugins = Plugins() plugins = Plugins()
p1 = AnalysisPlugin({'name': 'AnalysisP1', 'version': 0, 'description': 'No'}) p1 = AnalysisPlugin({'name': 'AnalysisP1', 'version': 0, 'description': 'No'})
plugins.plugins = [p1, ] plugins.plugins = [p1, ]
with patch_requests(plugins) as (request, response): with patch_requests('http://dummy/plugins', plugins):
response = client.plugins() response = client.plugins()
assert isinstance(response, dict) assert isinstance(response, dict)
assert len(response) == 1 assert len(response) == 1
assert "AnalysisP1" in response assert "AnalysisP1" in response
request.assert_called_with(
url=endpoint + '/plugins', method='GET',
params={})
...@@ -5,28 +5,29 @@ import json ...@@ -5,28 +5,29 @@ import json
from senpy.testing import patch_requests from senpy.testing import patch_requests
from senpy.models import Results from senpy.models import Results
ENDPOINT = 'http://example.com'
class TestTest(TestCase): class TestTest(TestCase):
def test_patch_text(self): def test_patch_text(self):
with patch_requests('hello'): with patch_requests(ENDPOINT, 'hello'):
r = requests.get('http://example.com') r = requests.get(ENDPOINT)
assert r.text == 'hello' assert r.text == 'hello'
assert r.content == 'hello'
def test_patch_json(self): def test_patch_json(self):
r = Results() r = Results()
with patch_requests(r): with patch_requests(ENDPOINT, r):
res = requests.get('http://example.com') res = requests.get(ENDPOINT)
assert res.content == json.dumps(r.jsonld()) assert res.text == json.dumps(r.jsonld())
js = res.json() js = res.json()
assert js assert js
assert js['@type'] == r['@type'] assert js['@type'] == r['@type']
def test_patch_dict(self): def test_patch_dict(self):
r = {'nothing': 'new'} r = {'nothing': 'new'}
with patch_requests(r): with patch_requests(ENDPOINT, r):
res = requests.get('http://example.com') res = requests.get(ENDPOINT)
assert res.content == json.dumps(r) assert res.text == json.dumps(r)
js = res.json() js = res.json()
assert js assert js
assert js['nothing'] == 'new' assert js['nothing'] == 'new'
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment