Skip to content

Commit 98a6a90

Browse files
committed
fix: Remove imports from conftest.py files, simplify the test files
1 parent a7aa7c3 commit 98a6a90

10 files changed

Lines changed: 234 additions & 139 deletions

File tree

tests/conftest.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,10 @@ def cleanup_mongo_clients():
1010
This fixture runs automatically after all tests complete.
1111
1212
"""
13-
# Let tests run
1413
yield
1514

16-
# Cleanup after all tests
1715
try:
18-
from tests.mongo_tests.conftest import _cleanup_mongo_client
16+
from tests.mongo_tests.helpers import _cleanup_mongo_client
1917
except ImportError:
2018
return
2119

tests/mongo_tests/conftest.py

Lines changed: 8 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -1,79 +1,12 @@
1-
"""Shared Mongo test configuration and helpers."""
1+
"""Shared Mongo test fixtures."""
22

3-
import platform
4-
import sys
5-
from contextlib import suppress
6-
from urllib.parse import quote_plus
3+
import pytest
74

8-
from birch import Birch # type: ignore[import-not-found]
5+
from .helpers import _cleanup_mongo_client
96

10-
try:
11-
from pymongo.mongo_client import MongoClient
12-
except (ImportError, ModuleNotFoundError):
137

14-
class MongoClient:
15-
"""Mock MongoClient class raising ImportError on missing pymongo."""
16-
17-
def __init__(self, *args, **kwargs):
18-
"""Initialize the mock MongoClient."""
19-
raise ImportError("pymongo is not installed!")
20-
21-
22-
try:
23-
from pymongo_inmemory import MongoClient as InMemoryMongoClient
24-
except (ImportError, ModuleNotFoundError):
25-
26-
class InMemoryMongoClient:
27-
"""Mock InMemoryMongoClient class.
28-
29-
Raises an ImportError on missing pymongo_inmemory.
30-
31-
"""
32-
33-
def __init__(self, *args, **kwargs):
34-
"""Initialize the mock InMemoryMongoClient."""
35-
raise ImportError("pymongo_inmemory is not installed!")
36-
37-
38-
class CfgKey:
39-
HOST = "TEST_HOST"
40-
PORT = "TEST_PORT"
41-
TEST_VS_DOCKERIZED_MONGO = "TEST_VS_DOCKERIZED_MONGO"
42-
43-
44-
CFG = Birch(namespace="cachier", defaults={CfgKey.TEST_VS_DOCKERIZED_MONGO: False})
45-
_COLLECTION_NAME = f"cachier_test_{platform.system()}_{'.'.join(map(str, sys.version_info[:3]))}"
46-
47-
48-
def _get_cachier_db_mongo_client():
49-
host = quote_plus(CFG[CfgKey.HOST])
50-
port = quote_plus(CFG[CfgKey.PORT])
51-
uri = f"mongodb://{host}:{port}?retrywrites=true&w=majority"
52-
return MongoClient(uri)
53-
54-
55-
def _test_mongetter():
56-
if not hasattr(_test_mongetter, "client"):
57-
if str(CFG.mget(CfgKey.TEST_VS_DOCKERIZED_MONGO)).lower() == "true":
58-
print("Using live MongoDB instance for testing.")
59-
_test_mongetter.client = _get_cachier_db_mongo_client()
60-
else:
61-
print("Using in-memory MongoDB instance for testing.")
62-
_test_mongetter.client = InMemoryMongoClient()
63-
db_obj = _test_mongetter.client["cachier_test"]
64-
if _COLLECTION_NAME not in db_obj.list_collection_names():
65-
db_obj.create_collection(_COLLECTION_NAME)
66-
return db_obj[_COLLECTION_NAME]
67-
68-
69-
def _cleanup_mongo_client():
70-
"""Close any cached Mongo test client safely."""
71-
client = getattr(_test_mongetter, "client", None)
72-
if client is None:
73-
return
74-
with suppress(Exception):
75-
client._mongod._client.close() # type: ignore[attr-defined]
76-
with suppress(Exception):
77-
client.close()
78-
with suppress(Exception):
79-
delattr(_test_mongetter, "client")
8+
@pytest.fixture(scope="session", autouse=True)
9+
def cleanup_mongo_client_fixture():
10+
"""Release cached Mongo client resources after the test session."""
11+
yield
12+
_cleanup_mongo_client()

tests/mongo_tests/helpers.py

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
"""Mongo test helpers: client configuration and shared mongetter."""
2+
3+
import platform
4+
import sys
5+
from contextlib import suppress
6+
from urllib.parse import quote_plus
7+
8+
from birch import Birch # type: ignore[import-not-found]
9+
10+
try:
11+
from pymongo.mongo_client import MongoClient
12+
except (ImportError, ModuleNotFoundError):
13+
14+
class MongoClient:
15+
"""Mock MongoClient raising ImportError when pymongo is missing."""
16+
17+
def __init__(self, *args, **kwargs):
18+
"""Initialize."""
19+
raise ImportError("pymongo is not installed!")
20+
21+
22+
try:
23+
from pymongo_inmemory import MongoClient as InMemoryMongoClient
24+
except (ImportError, ModuleNotFoundError):
25+
26+
class InMemoryMongoClient:
27+
"""Mock InMemoryMongoClient raising ImportError when pymongo_inmemory is missing."""
28+
29+
def __init__(self, *args, **kwargs):
30+
"""Initialize."""
31+
raise ImportError("pymongo_inmemory is not installed!")
32+
33+
34+
class CfgKey:
35+
HOST = "TEST_HOST"
36+
PORT = "TEST_PORT"
37+
TEST_VS_DOCKERIZED_MONGO = "TEST_VS_DOCKERIZED_MONGO"
38+
39+
40+
CFG = Birch(namespace="cachier", defaults={CfgKey.TEST_VS_DOCKERIZED_MONGO: False})
41+
_COLLECTION_NAME = f"cachier_test_{platform.system()}_{'.'.join(map(str, sys.version_info[:3]))}"
42+
43+
44+
def _get_cachier_db_mongo_client():
45+
host = quote_plus(CFG[CfgKey.HOST])
46+
port = quote_plus(CFG[CfgKey.PORT])
47+
uri = f"mongodb://{host}:{port}?retrywrites=true&w=majority"
48+
return MongoClient(uri)
49+
50+
51+
def _test_mongetter():
52+
if not hasattr(_test_mongetter, "client"):
53+
if str(CFG.mget(CfgKey.TEST_VS_DOCKERIZED_MONGO)).lower() == "true":
54+
print("Using live MongoDB instance for testing.")
55+
_test_mongetter.client = _get_cachier_db_mongo_client()
56+
else:
57+
print("Using in-memory MongoDB instance for testing.")
58+
_test_mongetter.client = InMemoryMongoClient()
59+
db_obj = _test_mongetter.client["cachier_test"]
60+
if _COLLECTION_NAME not in db_obj.list_collection_names():
61+
db_obj.create_collection(_COLLECTION_NAME)
62+
return db_obj[_COLLECTION_NAME]
63+
64+
65+
def _cleanup_mongo_client():
66+
"""Close any cached Mongo test client safely."""
67+
client = getattr(_test_mongetter, "client", None)
68+
if client is None:
69+
return
70+
with suppress(Exception):
71+
client._mongod._client.close() # type: ignore[attr-defined]
72+
with suppress(Exception):
73+
client.close()
74+
with suppress(Exception):
75+
delattr(_test_mongetter, "client")

tests/mongo_tests/test_mongo_core.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
from cachier.config import CacheEntry
3434
from cachier.cores.base import RecalculationNeeded
3535
from cachier.cores.mongo import _MongoCore
36-
from tests.mongo_tests.conftest import _test_mongetter
36+
from tests.mongo_tests.helpers import _test_mongetter
3737

3838
# === Enables testing vs a real MongoDB instance ===
3939

tests/redis_tests/conftest.py

Lines changed: 26 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1,59 +1,29 @@
1-
"""Shared Redis test configuration and helpers."""
1+
"""Shared Redis test fixtures."""
22

3-
import pytest
4-
from birch import Birch # type: ignore[import-not-found]
5-
6-
from .clients import _MockRedis
7-
8-
try:
9-
import redis
10-
11-
REDIS_AVAILABLE = True
12-
except ImportError:
13-
redis = None # type: ignore[assignment]
14-
REDIS_AVAILABLE = False
15-
16-
17-
class CfgKey:
18-
HOST = "TEST_REDIS_HOST"
19-
PORT = "TEST_REDIS_PORT"
20-
DB = "TEST_REDIS_DB"
21-
TEST_VS_DOCKERIZED_REDIS = "TEST_VS_DOCKERIZED_REDIS"
22-
23-
24-
CFG = Birch(
25-
namespace="cachier",
26-
defaults={CfgKey.TEST_VS_DOCKERIZED_REDIS: False},
27-
)
28-
29-
30-
def _get_test_redis_client():
31-
"""Get a Redis client for testing."""
32-
if not REDIS_AVAILABLE:
33-
pytest.skip("Redis not available")
34-
35-
if str(CFG.mget(CfgKey.TEST_VS_DOCKERIZED_REDIS)).lower() == "true":
36-
print("Using live Redis instance for testing.")
37-
host = CFG.get(CfgKey.HOST, "localhost")
38-
port = int(CFG.get(CfgKey.PORT, 6379))
39-
db = int(CFG.get(CfgKey.DB, 0))
40-
try:
41-
client = redis.Redis(host=host, port=port, db=db, decode_responses=False)
42-
client.ping()
43-
return client
44-
except redis.ConnectionError as e:
45-
print(f"Failed to connect to Redis: {e}")
46-
pytest.skip("Redis not available")
47-
else:
48-
print("Using mock Redis for testing.")
49-
return None
3+
from contextlib import suppress
504

5+
import pytest
516

52-
def _test_redis_getter():
53-
"""Get Redis client for testing."""
54-
client = _get_test_redis_client()
55-
if client is None:
56-
if not hasattr(_test_redis_getter, "_mock_client"):
57-
_test_redis_getter._mock_client = _MockRedis()
58-
return _test_redis_getter._mock_client
59-
return client
7+
from .clients import _AsyncInMemoryRedis, _MockRedis
8+
from .helpers import _get_test_redis_client
9+
10+
11+
@pytest.fixture
12+
def sync_redis_client_fixture():
13+
"""Yield a fresh sync Redis client for each test, cleared after use."""
14+
live_client = _get_test_redis_client()
15+
client = _MockRedis() if live_client is None else live_client
16+
yield client
17+
with suppress(Exception):
18+
if hasattr(client, "data"):
19+
client.data.clear()
20+
else:
21+
client.flushdb()
22+
23+
24+
@pytest.fixture
25+
def async_redis_client_fixture():
26+
"""Yield a fresh async in-memory Redis client for each test, cleared after use."""
27+
client = _AsyncInMemoryRedis()
28+
yield client
29+
client._data.clear()

tests/redis_tests/helpers.py

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
"""Redis test helpers: client configuration and shared getter."""
2+
3+
from typing import Optional
4+
5+
import pytest
6+
from birch import Birch # type: ignore[import-not-found]
7+
8+
from .clients import _MockRedis
9+
10+
try:
11+
import redis
12+
13+
REDIS_AVAILABLE = True
14+
except ImportError:
15+
redis = None # type: ignore[assignment]
16+
REDIS_AVAILABLE = False
17+
18+
19+
class CfgKey:
20+
HOST = "TEST_REDIS_HOST"
21+
PORT = "TEST_REDIS_PORT"
22+
DB = "TEST_REDIS_DB"
23+
TEST_VS_DOCKERIZED_REDIS = "TEST_VS_DOCKERIZED_REDIS"
24+
25+
26+
CFG = Birch(
27+
namespace="cachier",
28+
defaults={CfgKey.TEST_VS_DOCKERIZED_REDIS: False},
29+
)
30+
31+
_shared_mock_client: Optional[_MockRedis] = None
32+
33+
34+
def _get_test_redis_client():
35+
"""Return a live Redis client or None to indicate mock mode.
36+
37+
Calls pytest.skip() if the redis package is not installed.
38+
39+
"""
40+
if not REDIS_AVAILABLE:
41+
pytest.skip("Redis not available")
42+
43+
if str(CFG.mget(CfgKey.TEST_VS_DOCKERIZED_REDIS)).lower() == "true":
44+
print("Using live Redis instance for testing.")
45+
host = CFG.get(CfgKey.HOST, "localhost")
46+
port = int(CFG.get(CfgKey.PORT, 6379))
47+
db = int(CFG.get(CfgKey.DB, 0))
48+
try:
49+
client = redis.Redis(host=host, port=port, db=db, decode_responses=False)
50+
client.ping()
51+
return client
52+
except redis.ConnectionError as e:
53+
print(f"Failed to connect to Redis: {e}")
54+
pytest.skip("Redis not available")
55+
56+
print("Using mock Redis for testing.")
57+
return None
58+
59+
60+
def _test_redis_getter():
61+
"""Return a shared sync Redis client for tests (mock or live)."""
62+
global _shared_mock_client
63+
client = _get_test_redis_client()
64+
if client is not None:
65+
return client
66+
if _shared_mock_client is None:
67+
_shared_mock_client = _MockRedis()
68+
return _shared_mock_client

tests/redis_tests/test_redis_core.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
from cachier.core import _is_async_redis_client
1717
from cachier.cores.redis import MissingRedisClient, _RedisCore
1818
from tests.redis_tests.clients import _SyncInMemoryRedis
19-
from tests.redis_tests.conftest import REDIS_AVAILABLE, _get_test_redis_client, _test_redis_getter, redis
19+
from tests.redis_tests.helpers import REDIS_AVAILABLE, _get_test_redis_client, _test_redis_getter, redis
2020

2121
# === Redis core tests ===
2222

tests/sql_tests/conftest.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,6 @@
55
import pytest
66
import pytest_asyncio
77

8-
SQL_CONN_STR = os.environ.get("SQLALCHEMY_DATABASE_URL", "sqlite:///:memory:")
9-
108

119
def _get_async_sql_conn_str() -> str:
1210
conn_str = os.environ.get("SQLALCHEMY_DATABASE_URL")
@@ -21,6 +19,7 @@ def _get_async_sql_conn_str() -> str:
2119

2220
@pytest_asyncio.fixture
2321
async def async_sql_engine():
22+
"""Yield a fresh async SQL engine for each test, disposed after use."""
2423
pytest.importorskip("sqlalchemy.ext.asyncio")
2524
pytest.importorskip("greenlet")
2625
from sqlalchemy.ext.asyncio import create_async_engine

0 commit comments

Comments
 (0)