diff --git a/mycity/mycity/test/integration_tests/test_crime_incidents_api_utils.py b/mycity/mycity/test/integration_tests/test_crime_incidents_api_utils.py new file mode 100644 index 00000000..9966960e --- /dev/null +++ b/mycity/mycity/test/integration_tests/test_crime_incidents_api_utils.py @@ -0,0 +1,12 @@ +import unittest +import unittest.mock as mock +import requests +from mycity.utilities.crime_incidents_api_utils import get_crime_incident_response + + +class CrimeIncidentsAPIUtilitiesTestCase(unittest.TestCase): + + def test_get_crime_incident_response_returns_success_if_query_is_successful(self): + test_address = "46 Everdean St Boston, MA" + result = get_crime_incident_response(test_address) + self.assertEqual(True, result['success']) diff --git a/mycity/mycity/test/unit_tests/test_crime_incidents_api_utils.py b/mycity/mycity/test/unit_tests/test_crime_incidents_api_utils.py index 58d59c9e..7aa186b3 100644 --- a/mycity/mycity/test/unit_tests/test_crime_incidents_api_utils.py +++ b/mycity/mycity/test/unit_tests/test_crime_incidents_api_utils.py @@ -1,24 +1,23 @@ +import unittest import unittest.mock as mock -import mycity.test.test_constants as test_constants -import mycity.test.unit_tests.base as base -from mycity.utilities.crime_incidents_api_utils import \ - get_crime_incident_response +import requests +from mycity.utilities.crime_incidents_api_utils import get_crime_incident_response -class CrimeIncidentsAPIUtilitiesTestCase(base.BaseTestCase): - @mock.patch( - 'mycity.utilities.gis_utils.geocode_address', - return_value=test_constants.GEOCODE_ADDRESS_MOCK - ) - @mock.patch('requests.get') - def test_get_crime_incident_response(self, mock_geocode_address, mock_get): - mock_resp = self._mock_response(status=200, - json_data=test_constants.GET_CRIME_INCIDENTS_API_MOCK) - mock_get.return_value = mock_resp +class CrimeIncidentsAPIUtilitiesTestCase(unittest.TestCase): - test_address = "46 Everdean St Boston, MA" - result = get_crime_incident_response(test_address) - self.assertEqual( - True, - result['success'] - ) + def test_get_crime_incident_response_returns_empty_dict_if_request_fails(self): + test_session = mock.MagicMock() + test_session.response = mock.MagicMock() + test_session.response.status_code = requests.codes.bad + to_test = get_crime_incident_response('46 Everdean St.', test_session) + self.assertEquals({}, to_test) + + def test_get_crime_incident_response_returns_json_if_request_succeeds(self): + expected = 1 + test_session = mock.MagicMock() + test_session.response = mock.MagicMock() + test_session.response.status_code = requests.codes.ok + test_session.response.json = lambda: expected + to_test = get_crime_incident_response('46 Everdean St.', test_session) + self.assertEquals(expected, to_test) diff --git a/mycity/mycity/utilities/crime_incidents_api_utils.py b/mycity/mycity/utilities/crime_incidents_api_utils.py index cc1bcb44..047441bb 100644 --- a/mycity/mycity/utilities/crime_incidents_api_utils.py +++ b/mycity/mycity/utilities/crime_incidents_api_utils.py @@ -4,18 +4,22 @@ """ import requests -from mycity.utilities.gis_utils import geocode_address +import typing import logging +from mycity.utilities.gis_utils import geocode_address -RESOURCEID = "12cb3883-56f5-47de-afa5-3b1cf61b257b" + +RESOURCE_ID = "12cb3883-56f5-47de-afa5-3b1cf61b257b" QUERY_LIMIT = 5 CRIME_INCIDENTS_SQL_URL = \ "https://data.boston.gov/api/3/action/datastore_search_sql" +LONG_INDEX = 0 +LAT_INDEX = 1 logger = logging.getLogger(__name__) -def get_crime_incident_response(address): +def get_crime_incident_response(address: str, test_session: typing.ClassVar = None): """ Executes and returns the crime incident request response @@ -26,38 +30,45 @@ def get_crime_incident_response(address): url_parameters = {"sql": _build_query_string(address)} logger.debug("Finding crime incidents information for {} using query {}" .format(address, url_parameters)) + with requests.Session() as session: - response = session.get(CRIME_INCIDENTS_SQL_URL, params=url_parameters) + if test_session is None: + response = session.get(CRIME_INCIDENTS_SQL_URL, params=url_parameters) + else: + response = test_session.response if response.status_code == requests.codes.ok: return response.json() return {} -def _build_query_string(address): +def _build_query_string(address: str, test_get_coordinates: typing.Callable[[str], list] = None)-> str: """ Builds the SQL query given an address :param address: address to query + :param test_get_coordinates: injectable function for test :return: a SQL query string """ - coordinates = _get_coordinates_for_address(address) + coordinates = _get_coordinates_for_address(address) \ + if test_get_coordinates is None else test_get_coordinates(address) return """SELECT * FROM "{}" WHERE "lat" LIKE '{}%' AND \ "long" LIKE '{}%' LIMIT {}""" \ - .format(RESOURCEID, coordinates[0], coordinates[1], QUERY_LIMIT) + .format(RESOURCE_ID, coordinates[0], coordinates[1], QUERY_LIMIT) -def _get_coordinates_for_address(address): +def _get_coordinates_for_address(address: str, test_geocode_address: typing.Callable[[str], list] = None)-> tuple: """ Populates the GPS coordinates for the provided address :param address: address to query + :param test_geocode_address: injectable function for test :return: a tuple of the form (lat, long) """ - coordinates = geocode_address(address) + coordinates = geocode_address(address) if test_geocode_address is None else test_geocode_address(address) logger.debug("Got coordinates: {}".format(coordinates)) - _lat = "{:.2f}".format(float(coordinates[1])) - _long = "{:.2f}".format(float(coordinates[0])) - return (_lat, _long) \ No newline at end of file + _lat = "{:.2f}".format(float(coordinates[LAT_INDEX])) + _long = "{:.2f}".format(float(coordinates[LONG_INDEX])) + return _lat, _long