From cb9b148f9dc18d3b308abedfadb18fa4c7491216 Mon Sep 17 00:00:00 2001 From: Danny Hermes Date: Thu, 3 Nov 2016 22:34:02 -0700 Subject: [PATCH] Use mock library in natural language tests. --- language/tox.ini | 3 +- language/unit_tests/test_client.py | 64 +++++------ language/unit_tests/test_connection.py | 8 +- language/unit_tests/test_document.py | 140 ++++++++++++++----------- language/unit_tests/test_entity.py | 13 +-- language/unit_tests/test_sentiment.py | 11 +- language/unit_tests/test_syntax.py | 29 ++--- 7 files changed, 148 insertions(+), 120 deletions(-) diff --git a/language/tox.ini b/language/tox.ini index 9823ae7507a8..dd1ef21f61c8 100644 --- a/language/tox.ini +++ b/language/tox.ini @@ -5,6 +5,7 @@ envlist = [testing] deps = {toxinidir}/../core + mock pytest covercmd = py.test --quiet \ @@ -25,6 +26,6 @@ basepython = commands = {[testing]covercmd} deps = - {[testenv]deps} + {[testing]deps} coverage pytest-cov diff --git a/language/unit_tests/test_client.py b/language/unit_tests/test_client.py index 8b603cb8d832..d88eb7f0d316 100644 --- a/language/unit_tests/test_client.py +++ b/language/unit_tests/test_client.py @@ -17,28 +17,33 @@ class TestClient(unittest.TestCase): - def _getTargetClass(self): + @staticmethod + def _get_target_class(): from google.cloud.language.client import Client return Client - def _makeOne(self, *args, **kw): - return self._getTargetClass()(*args, **kw) + def _make_one(self, *args, **kw): + return self._get_target_class()(*args, **kw) def test_ctor(self): + import mock from google.cloud.language.connection import Connection - creds = _Credentials() + creds = mock.Mock() + creds.create_scoped_required.return_value = False http = object() - client = self._makeOne(credentials=creds, http=http) + client = self._make_one(credentials=creds, http=http) self.assertIsInstance(client.connection, Connection) self.assertIs(client.connection.credentials, creds) self.assertIs(client.connection.http, http) def test_document_from_text_factory(self): + import mock from google.cloud.language.document import Document - creds = _Credentials() - client = self._makeOne(credentials=creds, http=object()) + creds = mock.Mock() + creds.create_scoped_required.return_value = False + client = self._make_one(credentials=creds, http=object()) content = 'abc' language = 'es' @@ -52,17 +57,22 @@ def test_document_from_text_factory(self): self.assertEqual(document.language, language) def test_document_from_text_factory_failure(self): - creds = _Credentials() - client = self._makeOne(credentials=creds, http=object()) + import mock + + creds = mock.Mock() + creds.create_scoped_required.return_value = False + client = self._make_one(credentials=creds, http=object()) with self.assertRaises(TypeError): client.document_from_text('abc', doc_type='foo') def test_document_from_html_factory(self): + import mock from google.cloud.language.document import Document - creds = _Credentials() - client = self._makeOne(credentials=creds, http=object()) + creds = mock.Mock() + creds.create_scoped_required.return_value = False + client = self._make_one(credentials=creds, http=object()) content = 'abc' language = 'ja' @@ -76,17 +86,22 @@ def test_document_from_html_factory(self): self.assertEqual(document.language, language) def test_document_from_html_factory_failure(self): - creds = _Credentials() - client = self._makeOne(credentials=creds, http=object()) + import mock + + creds = mock.Mock() + creds.create_scoped_required.return_value = False + client = self._make_one(credentials=creds, http=object()) with self.assertRaises(TypeError): client.document_from_html('abc', doc_type='foo') def test_document_from_url_factory(self): + import mock from google.cloud.language.document import Document - creds = _Credentials() - client = self._makeOne(credentials=creds, http=object()) + creds = mock.Mock() + creds.create_scoped_required.return_value = False + client = self._make_one(credentials=creds, http=object()) gcs_url = 'gs://my-text-bucket/sentiment-me.txt' document = client.document_from_url(gcs_url) @@ -97,11 +112,13 @@ def test_document_from_url_factory(self): self.assertEqual(document.doc_type, Document.PLAIN_TEXT) def test_document_from_url_factory_explicit(self): + import mock from google.cloud.language.document import Document from google.cloud.language.document import Encoding - creds = _Credentials() - client = self._makeOne(credentials=creds, http=object()) + creds = mock.Mock() + creds.create_scoped_required.return_value = False + client = self._make_one(credentials=creds, http=object()) encoding = Encoding.UTF32 gcs_url = 'gs://my-text-bucket/sentiment-me.txt' @@ -113,16 +130,3 @@ def test_document_from_url_factory_explicit(self): self.assertEqual(document.gcs_url, gcs_url) self.assertEqual(document.doc_type, Document.HTML) self.assertEqual(document.encoding, encoding) - - -class _Credentials(object): - - _scopes = None - - @staticmethod - def create_scoped_required(): - return True - - def create_scoped(self, scope): - self._scopes = scope - return self diff --git a/language/unit_tests/test_connection.py b/language/unit_tests/test_connection.py index 694ec5ba3693..d2020c8575a3 100644 --- a/language/unit_tests/test_connection.py +++ b/language/unit_tests/test_connection.py @@ -17,15 +17,15 @@ class TestConnection(unittest.TestCase): - def _getTargetClass(self): + def _get_target_class(self): from google.cloud.language.connection import Connection return Connection - def _makeOne(self, *args, **kw): - return self._getTargetClass()(*args, **kw) + def _make_one(self, *args, **kw): + return self._get_target_class()(*args, **kw) def test_build_api_url(self): - conn = self._makeOne() + conn = self._make_one() uri = '/'.join([ conn.API_BASE_URL, conn.API_VERSION, diff --git a/language/unit_tests/test_document.py b/language/unit_tests/test_document.py index 836be446ea08..e422e0d8c7f0 100644 --- a/language/unit_tests/test_document.py +++ b/language/unit_tests/test_document.py @@ -97,19 +97,20 @@ def _get_entities(include_entities): class TestDocument(unittest.TestCase): - def _getTargetClass(self): + @staticmethod + def _get_target_class(): from google.cloud.language.document import Document return Document - def _makeOne(self, *args, **kw): - return self._getTargetClass()(*args, **kw) + def _make_one(self, *args, **kw): + return self._get_target_class()(*args, **kw) def test_constructor_defaults(self): import google.cloud.language.document as MUT client = object() content = 'abc' - document = self._makeOne(client, content) + document = self._make_one(client, content) self.assertIs(document.client, client) self.assertEqual(document.content, content) self.assertIsNone(document.gcs_url) @@ -123,10 +124,10 @@ def test_constructor_explicit(self): client = object() gcs_url = 'gs://some-bucket/some-obj.html' language = 'ja' - document = self._makeOne(client, gcs_url=gcs_url, - doc_type=MUT.Document.HTML, - language=language, - encoding=MUT.Encoding.UTF32) + document = self._make_one(client, gcs_url=gcs_url, + doc_type=MUT.Document.HTML, + language=language, + encoding=MUT.Encoding.UTF32) self.assertIs(document.client, client) self.assertIsNone(document.content) self.assertEqual(document.gcs_url, gcs_url) @@ -136,17 +137,17 @@ def test_constructor_explicit(self): def test_constructor_no_text(self): with self.assertRaises(ValueError): - self._makeOne(None, content=None, gcs_url=None) + self._make_one(None, content=None, gcs_url=None) def test_constructor_text_and_gcs(self): with self.assertRaises(ValueError): - self._makeOne(None, content='abc', - gcs_url='gs://some-bucket/some-obj.txt') + self._make_one(None, content='abc', + gcs_url='gs://some-bucket/some-obj.txt') def test__to_dict_with_content(self): - klass = self._getTargetClass() + klass = self._get_target_class() content = 'Hello World' - document = self._makeOne(None, content=content) + document = self._make_one(None, content=content) info = document._to_dict() self.assertEqual(info, { 'content': content, @@ -155,9 +156,9 @@ def test__to_dict_with_content(self): }) def test__to_dict_with_gcs(self): - klass = self._getTargetClass() + klass = self._get_target_class() gcs_url = 'gs://some-bucket/some-obj.html' - document = self._makeOne(None, gcs_url=gcs_url) + document = self._make_one(None, gcs_url=gcs_url) info = document._to_dict() self.assertEqual(info, { 'gcsContentUri': gcs_url, @@ -166,8 +167,8 @@ def test__to_dict_with_gcs(self): }) def test__to_dict_with_no_content(self): - klass = self._getTargetClass() - document = self._makeOne(None, content='') + klass = self._get_target_class() + document = self._make_one(None, content='') document.content = None # Manually unset the content. info = document._to_dict() self.assertEqual(info, { @@ -186,7 +187,37 @@ def _verify_entity(self, entity, name, entity_type, wiki_url, salience): self.assertEqual(entity.salience, salience) self.assertEqual(entity.mentions, [name]) + @staticmethod + def _expected_data(content, encoding_type=None, + extract_sentiment=False, + extract_entities=False, + extract_syntax=False): + from google.cloud.language.document import DEFAULT_LANGUAGE + from google.cloud.language.document import Document + + expected = { + 'document': { + 'language': DEFAULT_LANGUAGE, + 'type': Document.PLAIN_TEXT, + 'content': content, + }, + } + if encoding_type is not None: + expected['encodingType'] = encoding_type + if extract_sentiment: + features = expected.setdefault('features', {}) + features['extractDocumentSentiment'] = True + if extract_entities: + features = expected.setdefault('features', {}) + features['extractEntities'] = True + if extract_syntax: + features = expected.setdefault('features', {}) + features['extractSyntax'] = True + return expected + def test_analyze_entities(self): + import mock + from google.cloud.language.document import Encoding from google.cloud.language.entity import EntityType name1 = 'R-O-C-K' @@ -228,9 +259,10 @@ def test_analyze_entities(self): ], 'language': 'en-US', } - connection = _Connection(response) - client = _Client(connection=connection) - document = self._makeOne(client, content) + connection = mock.Mock() + connection.api_request.return_value = response + client = mock.Mock(connection=connection) + document = self._make_one(client, content) entities = document.analyze_entities() self.assertEqual(len(entities), 2) @@ -242,10 +274,10 @@ def test_analyze_entities(self): wiki2, salience2) # Verify the request. - self.assertEqual(len(connection._requested), 1) - req = connection._requested[0] - self.assertEqual(req['path'], 'analyzeEntities') - self.assertEqual(req['method'], 'POST') + expected = self._expected_data( + content, encoding_type=Encoding.UTF8) + connection.api_request.assert_called_once_with( + path='analyzeEntities', method='POST', data=expected) def _verify_sentiment(self, sentiment, polarity, magnitude): from google.cloud.language.sentiment import Sentiment @@ -255,6 +287,8 @@ def _verify_sentiment(self, sentiment, polarity, magnitude): self.assertEqual(sentiment.magnitude, magnitude) def test_analyze_sentiment(self): + import mock + content = 'All the pretty horses.' polarity = 1 magnitude = 0.6 @@ -265,18 +299,18 @@ def test_analyze_sentiment(self): }, 'language': 'en-US', } - connection = _Connection(response) - client = _Client(connection=connection) - document = self._makeOne(client, content) + connection = mock.Mock() + connection.api_request.return_value = response + client = mock.Mock(connection=connection) + document = self._make_one(client, content) sentiment = document.analyze_sentiment() self._verify_sentiment(sentiment, polarity, magnitude) # Verify the request. - self.assertEqual(len(connection._requested), 1) - req = connection._requested[0] - self.assertEqual(req['path'], 'analyzeSentiment') - self.assertEqual(req['method'], 'POST') + expected = self._expected_data(content) + connection.api_request.assert_called_once_with( + path='analyzeSentiment', method='POST', data=expected) def _verify_sentences(self, include_syntax, annotations): from google.cloud.language.syntax import Sentence @@ -305,7 +339,10 @@ def _verify_tokens(self, annotations, token_info): def _annotate_text_helper(self, include_sentiment, include_entities, include_syntax): + import mock + from google.cloud.language.document import Annotations + from google.cloud.language.document import Encoding from google.cloud.language.entity import EntityType token_info, sentences = _get_token_and_sentences(include_syntax) @@ -323,9 +360,10 @@ def _annotate_text_helper(self, include_sentiment, 'magnitude': ANNOTATE_MAGNITUDE, } - connection = _Connection(response) - client = _Client(connection=connection) - document = self._makeOne(client, ANNOTATE_CONTENT) + connection = mock.Mock() + connection.api_request.return_value = response + client = mock.Mock(connection=connection) + document = self._make_one(client, ANNOTATE_CONTENT) annotations = document.annotate_text( include_syntax=include_syntax, include_entities=include_entities, @@ -351,16 +389,13 @@ def _annotate_text_helper(self, include_sentiment, self.assertEqual(annotations.entities, []) # Verify the request. - self.assertEqual(len(connection._requested), 1) - req = connection._requested[0] - self.assertEqual(req['path'], 'annotateText') - self.assertEqual(req['method'], 'POST') - features = req['data']['features'] - self.assertEqual(features.get('extractDocumentSentiment', False), - include_sentiment) - self.assertEqual(features.get('extractEntities', False), - include_entities) - self.assertEqual(features.get('extractSyntax', False), include_syntax) + expected = self._expected_data( + ANNOTATE_CONTENT, encoding_type=Encoding.UTF8, + extract_sentiment=include_sentiment, + extract_entities=include_entities, + extract_syntax=include_syntax) + connection.api_request.assert_called_once_with( + path='annotateText', method='POST', data=expected) def test_annotate_text(self): self._annotate_text_helper(True, True, True) @@ -373,20 +408,3 @@ def test_annotate_text_entities_only(self): def test_annotate_text_syntax_only(self): self._annotate_text_helper(False, False, True) - - -class _Connection(object): - - def __init__(self, response): - self._response = response - self._requested = [] - - def api_request(self, **kwargs): - self._requested.append(kwargs) - return self._response - - -class _Client(object): - - def __init__(self, connection=None): - self.connection = connection diff --git a/language/unit_tests/test_entity.py b/language/unit_tests/test_entity.py index 33ea6d8fa1df..b595220f00bf 100644 --- a/language/unit_tests/test_entity.py +++ b/language/unit_tests/test_entity.py @@ -17,12 +17,13 @@ class TestEntity(unittest.TestCase): - def _getTargetClass(self): + @staticmethod + def _get_target_class(): from google.cloud.language.entity import Entity return Entity - def _makeOne(self, *args, **kw): - return self._getTargetClass()(*args, **kw) + def _make_one(self, *args, **kw): + return self._get_target_class()(*args, **kw) def test_constructor_defaults(self): name = 'Italian' @@ -33,8 +34,8 @@ def test_constructor_defaults(self): metadata.update(base_metadata) salience = 0.19960518 mentions = ['Italian'] - entity = self._makeOne(name, entity_type, metadata, - salience, mentions) + entity = self._make_one(name, entity_type, metadata, + salience, mentions) self.assertEqual(entity.name, name) self.assertEqual(entity.entity_type, entity_type) self.assertEqual(entity.wikipedia_url, wiki_url) @@ -43,7 +44,7 @@ def test_constructor_defaults(self): self.assertEqual(entity.mentions, mentions) def test_from_api_repr(self): - klass = self._getTargetClass() + klass = self._get_target_class() name = 'Italy' entity_type = 'LOCATION' salience = 0.223 diff --git a/language/unit_tests/test_sentiment.py b/language/unit_tests/test_sentiment.py index 356e7f781311..de545faca848 100644 --- a/language/unit_tests/test_sentiment.py +++ b/language/unit_tests/test_sentiment.py @@ -17,22 +17,23 @@ class TestSentiment(unittest.TestCase): - def _getTargetClass(self): + @staticmethod + def _get_target_class(): from google.cloud.language.sentiment import Sentiment return Sentiment - def _makeOne(self, *args, **kw): - return self._getTargetClass()(*args, **kw) + def _make_one(self, *args, **kw): + return self._get_target_class()(*args, **kw) def test_constructor(self): polarity = 1 magnitude = 2.3 - sentiment = self._makeOne(polarity, magnitude) + sentiment = self._make_one(polarity, magnitude) self.assertEqual(sentiment.polarity, polarity) self.assertEqual(sentiment.magnitude, magnitude) def test_from_api_repr(self): - klass = self._getTargetClass() + klass = self._get_target_class() polarity = -1 magnitude = 5.55 payload = { diff --git a/language/unit_tests/test_syntax.py b/language/unit_tests/test_syntax.py index 5f738fc56069..da6f09e54de4 100644 --- a/language/unit_tests/test_syntax.py +++ b/language/unit_tests/test_syntax.py @@ -17,12 +17,13 @@ class TestPartOfSpeech(unittest.TestCase): - def _getTargetClass(self): + @staticmethod + def _get_target_class(): from google.cloud.language.syntax import PartOfSpeech return PartOfSpeech def test_reverse(self): - klass = self._getTargetClass() + klass = self._get_target_class() for attr in dir(klass): if attr.startswith('_'): continue @@ -35,12 +36,13 @@ def test_reverse(self): class TestToken(unittest.TestCase): - def _getTargetClass(self): + @staticmethod + def _get_target_class(): from google.cloud.language.syntax import Token return Token - def _makeOne(self, *args, **kw): - return self._getTargetClass()(*args, **kw) + def _make_one(self, *args, **kw): + return self._get_target_class()(*args, **kw) def test_constructor(self): from google.cloud.language.syntax import PartOfSpeech @@ -51,8 +53,8 @@ def test_constructor(self): edge_index = 3 edge_label = 'PREDET' lemma = text_content - token = self._makeOne(text_content, text_begin, part_of_speech, - edge_index, edge_label, lemma) + token = self._make_one(text_content, text_begin, part_of_speech, + edge_index, edge_label, lemma) self.assertEqual(token.text_content, text_content) self.assertEqual(token.text_begin, text_begin) self.assertEqual(token.part_of_speech, part_of_speech) @@ -63,7 +65,7 @@ def test_constructor(self): def test_from_api_repr(self): from google.cloud.language.syntax import PartOfSpeech - klass = self._getTargetClass() + klass = self._get_target_class() text_content = 'pretty' text_begin = -1 part_of_speech = PartOfSpeech.ADJECTIVE @@ -95,22 +97,23 @@ def test_from_api_repr(self): class TestSentence(unittest.TestCase): - def _getTargetClass(self): + @staticmethod + def _get_target_class(): from google.cloud.language.syntax import Sentence return Sentence - def _makeOne(self, *args, **kw): - return self._getTargetClass()(*args, **kw) + def _make_one(self, *args, **kw): + return self._get_target_class()(*args, **kw) def test_constructor(self): content = "All the king's horses." begin = 11 - sentence = self._makeOne(content, begin) + sentence = self._make_one(content, begin) self.assertEqual(sentence.content, content) self.assertEqual(sentence.begin, begin) def test_from_api_repr(self): - klass = self._getTargetClass() + klass = self._get_target_class() content = 'All the pretty horses.' begin = -1 payload = {