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
Update test_jhu to handle asyncio
- Move test fixtures into tests/fixtures.py
- Update test fixtures to mock aiohttp.ClientSession.get, instead of requests.get
- Add a context manager to replace the global httputils.client_session with an AsyncMock
- Misc. cleanup
  • Loading branch information
james-gray committed Apr 2, 2020
commit 0e11daa44b8aeee1c700c9f5215092f4698e4446
89 changes: 89 additions & 0 deletions tests/fixtures.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import datetime
import os
from contextlib import asynccontextmanager
from unittest import mock

from app.utils import httputils


class DateTimeStrpTime:
"""Returns instance of `DateTimeStrpTime`
when calling `app.services.location.jhu.datetime.trptime(date, '%m/%d/%y').isoformat()`.
"""

def __init__(self, date, strformat):
self.date = date
self.strformat = strformat

def isoformat(self):
return datetime.datetime.strptime(self.date, self.strformat).isoformat()


class FakeRequestsGetResponse:
"""Fake instance of a response from `aiohttp.ClientSession.get`.
"""

def __init__(self, url, filename, state):
self.url = url
self.filename = filename
self.state = state

async def text(self):
return self.read_file(self.state)

def read_file(self, state):
"""
Mock HTTP GET-method and return text from file
"""
state = state.lower()

# Determine filepath.
filepath = os.path.join(os.path.dirname(__file__), "example_data/{}.csv".format(state))

# Return fake response.
print("Try to read {}".format(filepath))
with open(filepath, "r") as file:
return file.read()


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

:Example:

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

"""

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


@asynccontextmanager
async def mocked_session_get(*args, **kwargs):
"""Mock response from client_session.get.
"""

url = args[0]
filename = url.split("/")[-1]

# clean up for id token (e.g. Deaths)
state = filename.split("-")[-1].replace(".csv", "").lower().capitalize()

yield FakeRequestsGetResponse(url, filename, state)


def mocked_strptime_isoformat(*args, **kwargs):
"""Mock return value from datetime.strptime().isoformat().
"""

date = args[0]
strformat = args[1]

return DateTimeStrpTime(date, strformat)
83 changes: 14 additions & 69 deletions tests/test_jhu.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,81 +6,26 @@
import app
from app import location
from app.services.location import jhu
from app.utils import date
from tests.fixtures import mock_client_session
from tests.fixtures import mocked_session_get
from tests.fixtures import mocked_strptime_isoformat

DATETIME_STRING = "2020-03-17T10:23:22.505550"


def mocked_requests_get(*args, **kwargs):
class FakeRequestsGetResponse:
"""
Returns instance of `FakeRequestsGetResponse`
when calling `app.services.location.jhu.requests.get()`
"""

def __init__(self, url, filename, state):
self.url = url
self.filename = filename
self.state = state
self.text = self.read_file(self.state)

def read_file(self, state):
"""
Mock HTTP GET-method and return text from file
"""
state = state.lower()

# Determine filepath.
filepath = "tests/example_data/{}.csv".format(state)

# Return fake response.
print("Try to read {}".format(filepath))
with open(filepath, "r") as file:
return file.read()

# get url from `request.get`
url = args[0]

# get filename from url
filename = url.split("/")[-1]

# clean up for id token (e.g. Deaths)
state = filename.split("-")[-1].replace(".csv", "").lower().capitalize()

return FakeRequestsGetResponse(url, filename, state)


def mocked_strptime_isoformat(*args, **kwargs):
class DateTimeStrpTime:
"""
Returns instance of `DateTimeStrpTime`
when calling `app.services.location.jhu.datetime.trptime(date, '%m/%d/%y').isoformat()`
"""

def __init__(self, date, strformat):
self.date = date
self.strformat = strformat

def isoformat(self):
return datetime.datetime.strptime(self.date, self.strformat).isoformat()

date = args[0]
strformat = args[1]

return DateTimeStrpTime(date, strformat)


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

output = jhu.get_locations()
assert isinstance(output, list)
assert isinstance(output[0], location.Location)
async with mock_client_session() as mocked_client_session:
mocked_client_session.get = mocked_session_get
output = await jhu.get_locations()

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

# `jhu.get_locations()` creates id based on confirmed list
location_confirmed = 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"])