♻️ Replace pytest-mock with unittest.mock and remove pytest-cov (#717)

This commit is contained in:
Esteban Maya
2024-03-13 18:57:19 -05:00
committed by GitHub
parent a7deb9b39c
commit 85b7d6bc63
7 changed files with 112 additions and 163 deletions

View File

@@ -1,5 +1,6 @@
from unittest.mock import patch
from fastapi.testclient import TestClient from fastapi.testclient import TestClient
from pytest_mock import MockerFixture
from app.core.config import settings from app.core.config import settings
from app.utils import generate_password_reset_token from app.utils import generate_password_reset_token
@@ -39,18 +40,18 @@ def test_use_access_token(
def test_recovery_password( def test_recovery_password(
client: TestClient, normal_user_token_headers: dict[str, str], mocker: MockerFixture client: TestClient, normal_user_token_headers: dict[str, str]
) -> None: ) -> None:
mocker.patch("app.utils.send_email", return_value=None) with patch("app.core.config.settings.SMTP_HOST", "smtp.example.com"), patch(
mocker.patch("app.core.config.settings.SMTP_HOST", "smtp.example.com") "app.core.config.settings.SMTP_USER", "admin@example.com"
mocker.patch("app.core.config.settings.SMTP_USER", "admin@example.com") ):
email = "test@example.com" email = "test@example.com"
r = client.post( r = client.post(
f"{settings.API_V1_STR}/password-recovery/{email}", f"{settings.API_V1_STR}/password-recovery/{email}",
headers=normal_user_token_headers, headers=normal_user_token_headers,
) )
assert r.status_code == 200 assert r.status_code == 200
assert r.json() == {"message": "Password recovery email sent"} assert r.json() == {"message": "Password recovery email sent"}
def test_recovery_password_user_not_exits( def test_recovery_password_user_not_exits(

View File

@@ -1,5 +1,6 @@
from unittest.mock import patch
from fastapi.testclient import TestClient from fastapi.testclient import TestClient
from pytest_mock import MockerFixture
from sqlmodel import Session from sqlmodel import Session
from app import crud from app import crud
@@ -31,27 +32,24 @@ def test_get_users_normal_user_me(
def test_create_user_new_email( def test_create_user_new_email(
client: TestClient, client: TestClient, superuser_token_headers: dict[str, str], db: Session
superuser_token_headers: dict[str, str],
db: Session,
mocker: MockerFixture,
) -> None: ) -> None:
mocker.patch("app.utils.send_email") with patch("app.utils.send_email", return_value=None), patch(
mocker.patch("app.core.config.settings.SMTP_HOST", "smtp.example.com") "app.core.config.settings.SMTP_HOST", "smtp.example.com"
mocker.patch("app.core.config.settings.SMTP_USER", "admin@example.com") ), patch("app.core.config.settings.SMTP_USER", "admin@example.com"):
username = random_email() username = random_email()
password = random_lower_string() password = random_lower_string()
data = {"email": username, "password": password} data = {"email": username, "password": password}
r = client.post( r = client.post(
f"{settings.API_V1_STR}/users/", f"{settings.API_V1_STR}/users/",
headers=superuser_token_headers, headers=superuser_token_headers,
json=data, json=data,
) )
assert 200 <= r.status_code < 300 assert 200 <= r.status_code < 300
created_user = r.json() created_user = r.json()
user = crud.get_user_by_email(session=db, email=username) user = crud.get_user_by_email(session=db, email=username)
assert user assert user
assert user.email == created_user["email"] assert user.email == created_user["email"]
def test_get_existing_user( def test_get_existing_user(
@@ -265,55 +263,56 @@ def test_update_password_me_same_password_error(
) )
def test_create_user_open(client: TestClient, mocker: MockerFixture) -> None: def test_create_user_open(client: TestClient) -> None:
mocker.patch("app.core.config.settings.USERS_OPEN_REGISTRATION", True) with patch("app.core.config.settings.USERS_OPEN_REGISTRATION", True):
username = random_email() username = random_email()
password = random_lower_string() password = random_lower_string()
full_name = random_lower_string() full_name = random_lower_string()
data = {"email": username, "password": password, "full_name": full_name} data = {"email": username, "password": password, "full_name": full_name}
r = client.post( r = client.post(
f"{settings.API_V1_STR}/users/open", f"{settings.API_V1_STR}/users/open",
json=data, json=data,
) )
assert r.status_code == 200 assert r.status_code == 200
created_user = r.json() created_user = r.json()
assert created_user["email"] == username assert created_user["email"] == username
assert created_user["full_name"] == full_name assert created_user["full_name"] == full_name
def test_create_user_open_forbidden_error( def test_create_user_open_forbidden_error(client: TestClient) -> None:
client: TestClient, mocker: MockerFixture with patch("app.core.config.settings.USERS_OPEN_REGISTRATION", False):
) -> None: username = random_email()
mocker.patch("app.core.config.settings.USERS_OPEN_REGISTRATION", False) password = random_lower_string()
username = random_email() full_name = random_lower_string()
password = random_lower_string() data = {"email": username, "password": password, "full_name": full_name}
full_name = random_lower_string() r = client.post(
data = {"email": username, "password": password, "full_name": full_name} f"{settings.API_V1_STR}/users/open",
r = client.post( json=data,
f"{settings.API_V1_STR}/users/open", )
json=data, assert r.status_code == 403
) assert (
assert r.status_code == 403 r.json()["detail"] == "Open user registration is forbidden on this server"
assert r.json()["detail"] == "Open user registration is forbidden on this server" )
def test_create_user_open_already_exists_error( def test_create_user_open_already_exists_error(client: TestClient) -> None:
client: TestClient, mocker: MockerFixture with patch("app.core.config.settings.USERS_OPEN_REGISTRATION", True):
) -> None: password = random_lower_string()
mocker.patch("app.core.config.settings.USERS_OPEN_REGISTRATION", True) full_name = random_lower_string()
password = random_lower_string() data = {
full_name = random_lower_string() "email": settings.FIRST_SUPERUSER,
data = { "password": password,
"email": settings.FIRST_SUPERUSER, "full_name": full_name,
"password": password, }
"full_name": full_name, r = client.post(
} f"{settings.API_V1_STR}/users/open",
r = client.post( json=data,
f"{settings.API_V1_STR}/users/open", )
json=data, assert r.status_code == 400
) assert (
assert r.status_code == 400 r.json()["detail"]
assert r.json()["detail"] == "The user with this email already exists in the system" == "The user with this email already exists in the system"
)
def test_update_user( def test_update_user(

View File

@@ -1,33 +1,30 @@
from unittest.mock import MagicMock from unittest.mock import MagicMock, patch
from pytest_mock import MockerFixture
from sqlmodel import select from sqlmodel import select
from app.backend_pre_start import init, logger from app.backend_pre_start import init, logger
def test_init_successful_connection(mocker: MockerFixture) -> None: def test_init_successful_connection() -> None:
engine_mock = MagicMock() engine_mock = MagicMock()
session_mock = MagicMock() session_mock = MagicMock()
exec_mock = MagicMock(return_value=True) exec_mock = MagicMock(return_value=True)
session_mock.configure_mock(**{"exec.return_value": exec_mock}) session_mock.configure_mock(**{"exec.return_value": exec_mock})
mocker.patch("sqlmodel.Session", return_value=session_mock)
mocker.patch.object(logger, "info") with patch("sqlmodel.Session", return_value=session_mock), patch.object(
mocker.patch.object(logger, "error") logger, "info"
mocker.patch.object(logger, "warn") ), patch.object(logger, "error"), patch.object(logger, "warn"):
try:
init(engine_mock)
connection_successful = True
except Exception:
connection_successful = False
try: assert (
init(engine_mock) connection_successful
connection_successful = True ), "The database connection should be successful and not raise an exception."
except Exception:
connection_successful = False
assert ( assert session_mock.exec.called_once_with(
connection_successful select(1)
), "The database connection should be successful and not raise an exception." ), "The session should execute a select statement once."
assert session_mock.exec.called_once_with(
select(1)
), "The session should execute a select statement once."

View File

@@ -1,33 +1,30 @@
from unittest.mock import MagicMock from unittest.mock import MagicMock, patch
from pytest_mock import MockerFixture
from sqlmodel import select from sqlmodel import select
from app.tests_pre_start import init, logger from app.tests_pre_start import init, logger
def test_init_successful_connection(mocker: MockerFixture) -> None: def test_init_successful_connection() -> None:
engine_mock = MagicMock() engine_mock = MagicMock()
session_mock = MagicMock() session_mock = MagicMock()
exec_mock = MagicMock(return_value=True) exec_mock = MagicMock(return_value=True)
session_mock.configure_mock(**{"exec.return_value": exec_mock}) session_mock.configure_mock(**{"exec.return_value": exec_mock})
mocker.patch("sqlmodel.Session", return_value=session_mock)
mocker.patch.object(logger, "info") with patch("sqlmodel.Session", return_value=session_mock), patch.object(
mocker.patch.object(logger, "error") logger, "info"
mocker.patch.object(logger, "warn") ), patch.object(logger, "error"), patch.object(logger, "warn"):
try:
init(engine_mock)
connection_successful = True
except Exception:
connection_successful = False
try: assert (
init(engine_mock) connection_successful
connection_successful = True ), "The database connection should be successful and not raise an exception."
except Exception:
connection_successful = False
assert ( assert session_mock.exec.called_once_with(
connection_successful select(1)
), "The database connection should be successful and not raise an exception." ), "The session should execute a select statement once."
assert session_mock.exec.called_once_with(
select(1)
), "The session should execute a select statement once."

40
backend/poetry.lock generated
View File

@@ -379,9 +379,6 @@ files = [
{file = "coverage-7.4.3.tar.gz", hash = "sha256:276f6077a5c61447a48d133ed13e759c09e62aff0dc84274a68dc18660104d52"}, {file = "coverage-7.4.3.tar.gz", hash = "sha256:276f6077a5c61447a48d133ed13e759c09e62aff0dc84274a68dc18660104d52"},
] ]
[package.dependencies]
tomli = {version = "*", optional = true, markers = "python_full_version <= \"3.11.0a6\" and extra == \"toml\""}
[package.extras] [package.extras]
toml = ["tomli"] toml = ["tomli"]
@@ -1470,41 +1467,6 @@ tomli = {version = ">=1.0.0", markers = "python_version < \"3.11\""}
[package.extras] [package.extras]
testing = ["argcomplete", "attrs (>=19.2.0)", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"] testing = ["argcomplete", "attrs (>=19.2.0)", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"]
[[package]]
name = "pytest-cov"
version = "4.1.0"
description = "Pytest plugin for measuring coverage."
optional = false
python-versions = ">=3.7"
files = [
{file = "pytest-cov-4.1.0.tar.gz", hash = "sha256:3904b13dfbfec47f003b8e77fd5b589cd11904a21ddf1ab38a64f204d6a10ef6"},
{file = "pytest_cov-4.1.0-py3-none-any.whl", hash = "sha256:6ba70b9e97e69fcc3fb45bfeab2d0a138fb65c4d0d6a41ef33983ad114be8c3a"},
]
[package.dependencies]
coverage = {version = ">=5.2.1", extras = ["toml"]}
pytest = ">=4.6"
[package.extras]
testing = ["fields", "hunter", "process-tests", "pytest-xdist", "six", "virtualenv"]
[[package]]
name = "pytest-mock"
version = "3.12.0"
description = "Thin-wrapper around the mock package for easier use with pytest"
optional = false
python-versions = ">=3.8"
files = [
{file = "pytest-mock-3.12.0.tar.gz", hash = "sha256:31a40f038c22cad32287bb43932054451ff5583ff094bca6f675df2f8bc1a6e9"},
{file = "pytest_mock-3.12.0-py3-none-any.whl", hash = "sha256:0972719a7263072da3a21c7f4773069bcc7486027d7e8e1f81d98a47e701bc4f"},
]
[package.dependencies]
pytest = ">=5.0"
[package.extras]
dev = ["pre-commit", "pytest-asyncio", "tox"]
[[package]] [[package]]
name = "python-dateutil" name = "python-dateutil"
version = "2.9.0.post0" version = "2.9.0.post0"
@@ -2254,4 +2216,4 @@ files = [
[metadata] [metadata]
lock-version = "2.0" lock-version = "2.0"
python-versions = "^3.10" python-versions = "^3.10"
content-hash = "d1bf7cce2d9eb6d62051719a80e14eeb127722d116af04938775db6cbafe40cf" content-hash = "fcb0885e9c828f562a30c2690166bd1f41ce591779bb13deaaf6925463a53dda"

View File

@@ -29,13 +29,12 @@ sentry-sdk = {extras = ["fastapi"], version = "^1.40.6"}
[tool.poetry.group.dev.dependencies] [tool.poetry.group.dev.dependencies]
pytest = "^7.4.3" pytest = "^7.4.3"
pytest-cov = "^4.1.0"
mypy = "^1.8.0" mypy = "^1.8.0"
ruff = "^0.2.2" ruff = "^0.2.2"
pre-commit = "^3.6.2" pre-commit = "^3.6.2"
pytest-mock = "^3.12.0"
types-python-jose = "^3.3.4.20240106" types-python-jose = "^3.3.4.20240106"
types-passlib = "^1.7.7.20240106" types-passlib = "^1.7.7.20240106"
coverage = "^7.4.3"
[tool.isort] [tool.isort]
multi_line_output = 3 multi_line_output = 3

View File

@@ -1,6 +0,0 @@
#!/usr/bin/env bash
set -e
set -x
bash scripts/test.sh --cov-report=html "${@}"