Reputation: 3651
I need to simulate DB connection without actual connection. All answers I found are trying to mock methods in different ways, connect to docker db, connect to actual PostgreSQL running locally. I believe I need mocking variant but I cannot formulate in my head how should I mock. Am I missing something? Am I moving into wrong direction?
I use PostgreSQL and psycopg2. Package psycopg2-binary
Database connection:
import os
import psycopg2
from loguru import logger
from psycopg2.extensions import parse_dsn
def init_currency_history_table(cursor):
create_users_table_query = """
CREATE TABLE IF NOT EXISTS history(
id BIGINT PRIMARY KEY NOT NULL,
event TEXT,
creation_date TIMESTAMPTZ DEFAULT NOW()
);
"""
cursor.execute(create_users_table_query)
def load_db(db_url):
db = psycopg2.connect(**db_url)
db.autocommit = True
return db
class PostgresqlApi(object):
def __init__(self, load=load_db):
logger.info(os.environ.get('DATABASE_URL'))
db_url = parse_dsn(os.environ.get('DATABASE_URL'))
db_url['sslmode'] = 'require'
logger.info('HOST: {0}'.format(db_url.get('host')))
self.db = load_db(db_url)
self.cursor = self.db.cursor()
init_currency_history_table(self.cursor)
self.db.commit()
def add_event(self, *, event):
insert_event_table = """
INSERT INTO history (event) VALUES (%s);
"""
self.cursor.execute(insert_event_table, (event))
def events(self):
select_event_table = """SELECT * FROM event;"""
self.cursor.execute(select_event_table)
return self.cursor.fetchall()
def close(self):
self.cursor.close()
self.db.close()
I use DB for Falcon API.
from fastapi import Depends, FastAPI, HTTPException, status
from fastapi.security import HTTPBasic, HTTPBasicCredentials
from decimal import Decimal, getcontext
from db import PostgresqlApi
app = FastAPI()
security = HTTPBasic()
database = None
def db_connection():
global database
if not database:
database = PostgresqlApi()
return database
def check_basic_auth_creds(credentials: HTTPBasicCredentials = Depends(security)):
correct_username = secrets.compare_digest(credentials.username, os.environ.get('APP_USERNAME'))
correct_password = secrets.compare_digest(credentials.password, os.environ.get('APP_PASSWORD'))
if not (correct_username and correct_password):
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Incorrect username and password",
headers={'WWW-Authenticate': 'Basic'}
)
return credentials
@app.get("/currencies")
def read_currencies(credentials: HTTPBasicCredentials = Depends(check_basic_auth_creds)):
db = db_connection()
return {'get events': 'ok'}
I have tried different methods and plugins. Among others arepytest-pgsql
, pytest-postgresql
.
Upvotes: 5
Views: 3812
Reputation: 3651
The solution I landed at is below.
PostgresqlApi
. (see implementation below)db_connection
method. (see implementation below)Fake class implementation
class FakePostgresqlApi(PostgresqlApi):
event_list = []
def __init__(self):
pass
def add_event(self, *, event):
self.event_list.append([1, 'magic trick', 1653630607])
def events(self):
return self.event_list
def close(self):
self.event_list.clear()
Fixture
from unittest.mock import MagicMock
@pytest.fixture
def mock_db_connection(mocker):
mocker.patch('src.main.db_connection', MagicMock(return_value=FakePostgresqlApi()))
The test itself was:
def test_read_events(mock_db_connection):
# Do whatever I need here, in my case call Falcon API test client
Upvotes: 3