Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Mc add endpoint tests #14

Merged
merged 4 commits into from
May 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
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
6 changes: 2 additions & 4 deletions app.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,7 @@
api.add_resource(resource, endpoint, resource_class_kwargs=kwargs)


def create_app() -> Flask:
psycopg2_connection = initialize_psycopg2_connection()

def create_app(psycopg2_connection) -> Flask:

Check warning on line 28 in app.py

View workflow job for this annotation

GitHub Actions / flake8

[flake8] app.py#L28 <103>

Missing docstring in public function
Raw output
./app.py:28:1: D103 Missing docstring in public function
app = Flask(__name__)
api = Api(app)
CORS(app)
Expand Down Expand Up @@ -57,5 +55,5 @@


if __name__ == "__main__":
app = create_app()
app = create_app(initialize_psycopg2_connection())
app.run(debug=True, host="0.0.0.0")
12 changes: 0 additions & 12 deletions resources/PsycopgResource.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,15 +48,3 @@ def __init__(self, **kwargs):
- kwargs (dict): Keyword arguments containing 'psycopg2_connection' for database connection.
"""
self.psycopg2_connection = kwargs["psycopg2_connection"]

def get(self):
"""
Base implementation of GET. Override in subclasses as needed.
"""
raise NotImplementedError("This method should be overridden by subclasses")

def post(self):
"""
Base implementation of POST. Override in subclasses as needed.
"""
raise NotImplementedError("This method should be overridden by subclasses")
17 changes: 2 additions & 15 deletions tests/resources/app_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,20 +32,9 @@


@pytest.fixture()
def test_app_with_mock():
def test_app_with_mock(mocker):

Check warning on line 35 in tests/resources/app_test.py

View workflow job for this annotation

GitHub Actions / flake8

[flake8] tests/resources/app_test.py#L35 <103>

Missing docstring in public function
Raw output
./tests/resources/app_test.py:35:1: D103 Missing docstring in public function
# Patch the initialize_psycopg2_connection function so it returns a MagicMock
with patch("app.initialize_psycopg2_connection") as mock_init:
mock_connection = MagicMock()
mock_init.return_value = mock_connection

app = create_app()
# If your app stores the connection in a global or app context,
# you can also directly assign the mock_connection there

# Provide access to the mock within the app for assertions in tests
app.mock_connection = mock_connection

yield app
yield create_app(mocker.MagicMock())


@pytest.fixture()
Expand Down Expand Up @@ -171,8 +160,6 @@
json_data = response.get_json()
assert "api_key" in json_data
assert response.status_code == 200
test_app_with_mock.mock_connection.cursor().execute.assert_called_once()
test_app_with_mock.mock_connection.commit.assert_called_once()


# endregion
113 changes: 113 additions & 0 deletions tests/test_endpoints.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
"""

Check warning on line 1 in tests/test_endpoints.py

View workflow job for this annotation

GitHub Actions / flake8

[flake8] tests/test_endpoints.py#L1 <205>

1 blank line required between summary line and description
Raw output
./tests/test_endpoints.py:1:1: D205 1 blank line required between summary line and description

Check warning on line 1 in tests/test_endpoints.py

View workflow job for this annotation

GitHub Actions / flake8

[flake8] tests/test_endpoints.py#L1 <400>

First line should end with a period
Raw output
./tests/test_endpoints.py:1:1: D400 First line should end with a period
This module tests the functionality of all endpoints, ensuring that, as designed, they call (or don't call)
the appropriate methods in their supporting classes
"""

from collections import namedtuple
from typing import Type, Any, List

Check warning on line 7 in tests/test_endpoints.py

View workflow job for this annotation

GitHub Actions / flake8

[flake8] tests/test_endpoints.py#L7 <401>

'typing.Type' imported but unused
Raw output
./tests/test_endpoints.py:7:1: F401 'typing.Type' imported but unused

Check warning on line 7 in tests/test_endpoints.py

View workflow job for this annotation

GitHub Actions / flake8

[flake8] tests/test_endpoints.py#L7 <401>

'typing.Any' imported but unused
Raw output
./tests/test_endpoints.py:7:1: F401 'typing.Any' imported but unused

Check warning on line 7 in tests/test_endpoints.py

View workflow job for this annotation

GitHub Actions / flake8

[flake8] tests/test_endpoints.py#L7 <401>

'typing.List' imported but unused
Raw output
./tests/test_endpoints.py:7:1: F401 'typing.List' imported but unused

import pytest
from unittest.mock import patch

from flask.testing import FlaskClient
from flask_restful import Resource

from app import create_app
from resources.Agencies import Agencies
from resources.ApiKey import ApiKey
from resources.Archives import Archives
from resources.DataSources import (
DataSources,
DataSourcesMap,
DataSourcesNeedsIdentification,
DataSourceById,
)
from resources.Login import Login
from resources.QuickSearch import QuickSearch
from resources.RefreshSession import RefreshSession
from resources.RequestResetPassword import RequestResetPassword
from resources.ResetPassword import ResetPassword
from resources.ResetTokenValidation import ResetTokenValidation
from resources.SearchTokens import SearchTokens
from resources.User import User


# Define constants for HTTP methods
GET = "get"
POST = "post"
PUT = "put"
DELETE = "delete"


@pytest.fixture
def client(mocker) -> FlaskClient:
"""

Check warning on line 44 in tests/test_endpoints.py

View workflow job for this annotation

GitHub Actions / flake8

[flake8] tests/test_endpoints.py#L44 <205>

1 blank line required between summary line and description
Raw output
./tests/test_endpoints.py:44:1: D205 1 blank line required between summary line and description

Check warning on line 44 in tests/test_endpoints.py

View workflow job for this annotation

GitHub Actions / flake8

[flake8] tests/test_endpoints.py#L44 <400>

First line should end with a period
Raw output
./tests/test_endpoints.py:44:1: D400 First line should end with a period
Create a client with a mocked database connection
:param mocker:
:return:
"""
app = create_app(mocker.MagicMock())
with app.test_client() as client:
yield client


def run_endpoint_tests(

Check warning on line 54 in tests/test_endpoints.py

View workflow job for this annotation

GitHub Actions / flake8

[flake8] tests/test_endpoints.py#L54 <103>

Missing docstring in public function
Raw output
./tests/test_endpoints.py:54:1: D103 Missing docstring in public function
client: FlaskClient, endpoint: str, class_type: Resource, allowed_methods: list[str]
):
methods = [GET, POST, PUT, DELETE]
for method in methods:
if method in allowed_methods:
with patch.object(
class_type, method, return_value="Mocked response"
) as mock_method:
response = getattr(client, method)(endpoint)
assert (
response.status_code == 200
), f"{method.upper()} {endpoint} failed with status code {response.status_code}, expected 200"
mock_method.assert_called_once(), f"{method.upper()} {endpoint} should have called the {method} method on {class_type.__name__}"
else:
response = getattr(client, method)(endpoint)
assert (
response.status_code == 405
), f"{method.upper()} {endpoint} failed with status code {response.status_code}, expected 405"


TestParameters = namedtuple("Resource", ["class_type", "endpoint", "allowed_methods"])
test_parameters = [
TestParameters(User, "/user", [POST, PUT]),
TestParameters(Login, "/login", [POST]),
TestParameters(RefreshSession, "/refresh-session", [POST]),
TestParameters(ApiKey, "/api_key", [GET]),
TestParameters(RequestResetPassword, "/request-reset-password", [POST]),
TestParameters(ResetPassword, "/reset-password", [POST]),
TestParameters(ResetTokenValidation, "/reset-token-validation", [POST]),
TestParameters(QuickSearch, "/quick-search/<search>/<location>", [GET]),
TestParameters(Archives, "/archives", [GET, PUT]),
TestParameters(DataSources, "/data-sources", [GET, POST]),
TestParameters(DataSourcesMap, "/data-sources-map", [GET]),
TestParameters(
DataSourcesNeedsIdentification, "/data-sources-needs-identification", [GET]
),
TestParameters(DataSourceById, "/data-sources-by-id/<data_source_id>", [GET, PUT]),
TestParameters(Agencies, "/agencies/<page>", [GET]),
TestParameters(SearchTokens, "/search-tokens", [GET]),
]


@pytest.mark.parametrize("test_parameter", test_parameters)
def test_endpoints(client: FlaskClient, test_parameter) -> None:
"""

Check warning on line 99 in tests/test_endpoints.py

View workflow job for this annotation

GitHub Actions / flake8

[flake8] tests/test_endpoints.py#L99 <205>

1 blank line required between summary line and description
Raw output
./tests/test_endpoints.py:99:1: D205 1 blank line required between summary line and description

Check warning on line 99 in tests/test_endpoints.py

View workflow job for this annotation

GitHub Actions / flake8

[flake8] tests/test_endpoints.py#L99 <400>

First line should end with a period
Raw output
./tests/test_endpoints.py:99:1: D400 First line should end with a period
Using the test_parameters list, this tests all endpoints to ensure that
only the appropriate methods can be called from the endpoints
:param client: the client fixture
:param class_type:
:param endpoint:
:param allowed_methods:
:return:
"""
run_endpoint_tests(
client,
test_parameter.endpoint,
test_parameter.class_type,
test_parameter.allowed_methods,
)
Loading