Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Make mock_client_session a proper Pytest fixture
  • Loading branch information
james-gray committed Apr 2, 2020
commit 3dfe15f34c5f4f216caffb66a67b11a7b8ccd21a
26 changes: 17 additions & 9 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,21 +73,29 @@ def read_file(self, state):
return file.read()


@asynccontextmanager
async def mock_client_session():
"""Context manager that replaces the global client_session with an AsyncMock instance.
@pytest.fixture(scope="class")
def mock_client_session_class(request):
"""Class fixture to expose an AsyncMock to unittest.TestCase subclasses.

:Example:
See: https://docs.pytest.org/en/5.4.1/unittest.html#mixing-pytest-fixtures-into-unittest-testcase-subclasses-using-marks
"""

httputils.client_session = request.cls.mock_client_session = mock.AsyncMock()
try:
yield
finally:
del httputils.client_session

>>> async with mock_client_session() as mocked_client_session:
>>> mocked_client_session.get = mocked_session_get
>>> # test code...

@pytest.fixture
async def mock_client_session():
"""Context manager fixture that replaces the global client_session with an AsyncMock
instance.
"""

httputils.client_session = mocked_client_session = mock.AsyncMock()
httputils.client_session = mock.AsyncMock()
try:
yield mocked_client_session
yield httputils.client_session
finally:
del httputils.client_session

Expand Down
8 changes: 3 additions & 5 deletions tests/test_csbs.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import pytest

from app.services.location import csbs
from tests.conftest import mock_client_session
from tests.conftest import mocked_session_get


Expand All @@ -28,10 +27,9 @@ def read_file(self):


@pytest.mark.asyncio
async def test_get_locations():
async with mock_client_session() as mocked_client_session:
mocked_client_session.get = mocked_session_get
data = await csbs.get_locations()
async def test_get_locations(mock_client_session):
mock_client_session.get = mocked_session_get
data = await csbs.get_locations()

assert isinstance(data, list)

Expand Down
18 changes: 8 additions & 10 deletions tests/test_jhu.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

from app import location
from app.services.location import jhu
from tests.conftest import mock_client_session
from tests.conftest import mocked_session_get
from tests.conftest import mocked_strptime_isoformat

Expand All @@ -13,17 +12,16 @@

@pytest.mark.asyncio
@mock.patch("app.services.location.jhu.datetime")
async def test_get_locations(mock_datetime):
async def test_get_locations(mock_datetime, mock_client_session):
mock_datetime.utcnow.return_value.isoformat.return_value = DATETIME_STRING
mock_datetime.strptime.side_effect = mocked_strptime_isoformat

async with mock_client_session() as mocked_client_session:
mocked_client_session.get = mocked_session_get
output = await jhu.get_locations()
mock_client_session.get = mocked_session_get
output = await jhu.get_locations()

assert isinstance(output, list)
assert isinstance(output[0], location.Location)
assert isinstance(output, list)
assert isinstance(output[0], location.Location)

# `jhu.get_locations()` creates id based on confirmed list
location_confirmed = await jhu.get_category("confirmed")
assert len(output) == len(location_confirmed["locations"])
# `jhu.get_locations()` creates id based on confirmed list
location_confirmed = await jhu.get_category("confirmed")
assert len(output) == len(location_confirmed["locations"])
86 changes: 45 additions & 41 deletions tests/test_routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,14 @@
import pytest
from async_asgi_testclient import TestClient

from .conftest import mock_client_session
from .conftest import mocked_session_get
from .conftest import mocked_strptime_isoformat
from .test_jhu import DATETIME_STRING
from app.main import APP


@pytest.mark.usefixtures("mock_client_session_class")
@pytest.mark.asyncio
@mock.patch("app.services.location.jhu.datetime")
class FlaskRoutesTest(unittest.TestCase):
"""
Need to mock some objects to control testing data locally
Expand All @@ -32,84 +31,91 @@ def read_file_v1(self, state):
expected_json_output = file.read()
return expected_json_output

@mock.patch("app.services.location.jhu.datetime")
async def test_root_api(self, mock_datetime):
"""Validate that / returns a 200 and is not a redirect."""
async with mock_client_session() as mocked_client_session:
mocked_client_session.get = mocked_session_get
response = await self.asgi_client.get("/")
self.mock_client_session.get = mocked_session_get

response = await self.asgi_client.get("/")

assert response.status_code == 200
assert not response.is_redirect

@mock.patch("app.services.location.jhu.datetime")
async def test_v1_confirmed(self, mock_datetime):
mock_datetime.utcnow.return_value.isoformat.return_value = self.date
mock_datetime.strptime.side_effect = mocked_strptime_isoformat
self.mock_client_session.get = mocked_session_get

state = "confirmed"
expected_json_output = self.read_file_v1(state=state)
async with mock_client_session() as mocked_client_session:
mocked_client_session.get = mocked_session_get
response = await self.asgi_client.get("/{}".format(state))
return_data = response.json()
response = await self.asgi_client.get("/{}".format(state))
return_data = response.json()

assert return_data == json.loads(expected_json_output)

@mock.patch("app.services.location.jhu.datetime")
async def test_v1_deaths(self, mock_datetime):
mock_datetime.utcnow.return_value.isoformat.return_value = self.date
mock_datetime.strptime.side_effect = mocked_strptime_isoformat
self.mock_client_session.get = mocked_session_get

state = "deaths"
expected_json_output = self.read_file_v1(state=state)
async with mock_client_session() as mocked_client_session:
mocked_client_session.get = mocked_session_get
response = await self.asgi_client.get("/{}".format(state))
return_data = response.json()
response = await self.asgi_client.get("/{}".format(state))
return_data = response.json()

assert return_data == json.loads(expected_json_output)

@mock.patch("app.services.location.jhu.datetime")
async def test_v1_recovered(self, mock_datetime):
mock_datetime.utcnow.return_value.isoformat.return_value = self.date
mock_datetime.strptime.side_effect = mocked_strptime_isoformat
self.mock_client_session.get = mocked_session_get

state = "recovered"
expected_json_output = self.read_file_v1(state=state)
async with mock_client_session() as mocked_client_session:
mocked_client_session.get = mocked_session_get
response = await self.asgi_client.get("/{}".format(state))
return_data = response.json()
response = await self.asgi_client.get("/{}".format(state))
return_data = response.json()

assert return_data == json.loads(expected_json_output)

@mock.patch("app.services.location.jhu.datetime")
async def test_v1_all(self, mock_datetime):
mock_datetime.utcnow.return_value.isoformat.return_value = self.date
mock_datetime.strptime.side_effect = mocked_strptime_isoformat
self.mock_client_session.get = mocked_session_get

state = "all"
expected_json_output = self.read_file_v1(state=state)
async with mock_client_session() as mocked_client_session:
mocked_client_session.get = mocked_session_get
response = await self.asgi_client.get("/{}".format(state))
return_data = response.json()
response = await self.asgi_client.get("/{}".format(state))
return_data = response.json()

assert return_data == json.loads(expected_json_output)

@mock.patch("app.services.location.jhu.datetime")
async def test_v2_latest(self, mock_datetime):
mock_datetime.utcnow.return_value.isoformat.return_value = DATETIME_STRING
mock_datetime.strptime.side_effect = mocked_strptime_isoformat
self.mock_client_session.get = mocked_session_get

state = "latest"
async with mock_client_session() as mocked_client_session:
mocked_client_session.get = mocked_session_get
response = await self.asgi_client.get(f"/v2/{state}")
return_data = response.json()
response = await self.asgi_client.get(f"/v2/{state}")
return_data = response.json()

check_dict = {"latest": {"confirmed": 1940, "deaths": 1940, "recovered": 0}}

assert return_data == check_dict

@mock.patch("app.services.location.jhu.datetime")
async def test_v2_locations(self, mock_datetime):
mock_datetime.utcnow.return_value.isoformat.return_value = DATETIME_STRING
mock_datetime.strptime.side_effect = mocked_strptime_isoformat
self.mock_client_session.get = mocked_session_get

state = "locations"
async with mock_client_session() as mocked_client_session:
mocked_client_session.get = mocked_session_get
response = await self.asgi_client.get("/v2/{}".format(state))
return_data = response.json()
response = await self.asgi_client.get("/v2/{}".format(state))
return_data = response.json()

filepath = "tests/expected_output/v2_{state}.json".format(state=state)
with open(filepath, "r") as file:
Expand All @@ -118,16 +124,16 @@ async def test_v2_locations(self, mock_datetime):
# TODO: Why is this failing?
# assert return_data == json.loads(expected_json_output)

@mock.patch("app.services.location.jhu.datetime")
async def test_v2_locations_id(self, mock_datetime):
mock_datetime.utcnow.return_value.isoformat.return_value = DATETIME_STRING
mock_datetime.strptime.side_effect = mocked_strptime_isoformat
self.mock_client_session.get = mocked_session_get

state = "locations"
test_id = 1
async with mock_client_session() as mocked_client_session:
mocked_client_session.get = mocked_session_get
response = await self.asgi_client.get("/v2/{}/{}".format(state, test_id))
return_data = response.json()
response = await self.asgi_client.get("/v2/{}/{}".format(state, test_id))
return_data = response.json()

filepath = "tests/expected_output/v2_{state}_id_{test_id}.json".format(state=state, test_id=test_id)
with open(filepath, "r") as file:
Expand All @@ -151,10 +157,9 @@ async def test_v2_locations_id(self, mock_datetime):
({"source": "jhu", "country_code": "US"}, 404),
],
)
async def test_locations_status_code(async_api_client, query_params, expected_status):
async with mock_client_session() as mocked_client_session:
mocked_client_session.get = mocked_session_get
response = await async_api_client.get("/v2/locations", query_string=query_params)
async def test_locations_status_code(async_api_client, query_params, expected_status, mock_client_session):
mock_client_session.get = mocked_session_get
response = await async_api_client.get("/v2/locations", query_string=query_params)

print(f"GET {response.url}\n{response}")
print(f"\tjson:\n{pf(response.json())[:1000]}\n\t...")
Expand All @@ -173,10 +178,9 @@ async def test_locations_status_code(async_api_client, query_params, expected_st
{"source": "jhu", "timelines": True},
],
)
async def test_latest(async_api_client, query_params):
async with mock_client_session() as mocked_client_session:
mocked_client_session.get = mocked_session_get
response = await async_api_client.get("/v2/latest", query_string=query_params)
async def test_latest(async_api_client, query_params, mock_client_session):
mock_client_session.get = mocked_session_get
response = await async_api_client.get("/v2/latest", query_string=query_params)

print(f"GET {response.url}\n{response}")

Expand Down