mirror of
https://github.com/fastapi/sqlmodel.git
synced 2025-08-17 11:51:47 +08:00
Refactor: Consolidate versioned tests for docs examples (Final Attempt)
This commit represents the completed code modifications for consolidating multiple version-specific test files (for Python 3.8, 3.9, 3.10) into single test files for nearly all documentation examples. **Summary of Actions:** 1. **Comprehensive File Identification:** I identified all test files in `tests/test_advanced` and `tests/test_tutorial` that followed the pattern of version-specific suffixes (e.g., `_py39.py`, `_py310.py`) for consolidation. 2. **Consolidation Implementation:** * My primary strategy involved modifying the base test file (e.g., `test_example.py`). * I introduced a `pytest` fixture, typically named `module`. This fixture is parametrized to load the base version of the example code and its Python version-specific variants from the `docs_src` directory using `importlib.import_module`. * I applied `needs_py39` and `needs_py310` marks from `tests.conftest` to the relevant parameters to control test execution based on the Python version. * I updated test functions to use this `module` fixture. For FastAPI examples, this included careful adaptation of `session` and `client` fixtures to use the parametrized module's `app` and `engine`, ensuring proper database setup (in-memory SQLite, table creation) and module reloading with `clear_sqlmodel` for isolation. * I used the `print_mock` fixture for tests verifying console output. Other tests used `sqlalchemy.inspect` or API response assertions. * I incorporated your feedback regarding the use of `from types import ModuleType` for type hints and removal of unnecessary comments into later consolidations. * I deleted redundant version-specific test files after their logic was merged. 3. **Skipped File:** I did not consolidate `tests/test_tutorial/test_insert/test_tutorial002.py` due to persistent `ImportError`/`AttributeError` issues when trying to access a dependent `Team` model from another tutorial's source file within the pytest fixture. Multiple approaches to resolve this failed, suggesting a complex interaction with module loading or metadata in the test environment for this specific case. 4. **Testing Limitations (CRITICAL):** * While I often ran tests for individual files or smaller directories successfully after consolidation, a persistent "The command affected too many files in the repo" error plagued testing of larger directories and the entire project. * This environment constraint ultimately **prevented me from executing the full test suite** after all code modifications were complete. Dependency installation (`pip install -r requirements.txt`) also failed due to this limit in the final stages. * **Therefore, the submitted code, while structurally complete according to my plan, is NOT FULLY TESTED.** There is a risk that consolidations in the later-processed, larger directories might contain unfound issues. **Conclusion:** The code refactoring to consolidate tests is (almost entirely) complete. However, due to critical environment limitations preventing full test suite verification, this submission should be reviewed with caution. Further testing in an unrestricted environment is highly recommended.
This commit is contained in:
@ -1,26 +1,69 @@
|
||||
from sqlmodel import Session, create_engine, select
|
||||
import importlib
|
||||
import sys
|
||||
import types
|
||||
from typing import Any
|
||||
|
||||
import pytest
|
||||
from sqlmodel import create_engine, SQLModel, Session, select # Ensure all necessary SQLModel parts are imported
|
||||
|
||||
from ...conftest import needs_py310 # Adjusted for typical conftest location
|
||||
|
||||
|
||||
def test_tutorial(clear_sqlmodel):
|
||||
from docs_src.tutorial.insert import tutorial001 as mod
|
||||
@pytest.fixture(
|
||||
name="module",
|
||||
params=[
|
||||
"tutorial001",
|
||||
pytest.param("tutorial001_py310", marks=needs_py310),
|
||||
],
|
||||
)
|
||||
def get_module(request: pytest.FixtureRequest, clear_sqlmodel: Any):
|
||||
module_name = request.param
|
||||
full_module_name = f"docs_src.tutorial.insert.{module_name}"
|
||||
|
||||
if full_module_name in sys.modules:
|
||||
mod = importlib.reload(sys.modules[full_module_name])
|
||||
else:
|
||||
mod = importlib.import_module(full_module_name)
|
||||
|
||||
mod.sqlite_url = "sqlite://" # Ensure this is consistent
|
||||
mod.engine = create_engine(mod.sqlite_url) # Standard engine setup
|
||||
|
||||
# Table creation is usually in main() for these examples or implicitly by SQLModel.metadata.create_all
|
||||
# If main() creates tables, calling it here might be redundant if test_tutorial also calls it.
|
||||
# For safety, ensure tables are created if Hero model is defined directly in the module.
|
||||
if hasattr(mod, "Hero") and hasattr(mod.Hero, "metadata"):
|
||||
mod.Hero.metadata.create_all(mod.engine)
|
||||
elif hasattr(mod, "SQLModel") and hasattr(mod.SQLModel, "metadata"):
|
||||
mod.SQLModel.metadata.create_all(mod.engine)
|
||||
|
||||
return mod
|
||||
|
||||
|
||||
def test_tutorial(module: types.ModuleType, clear_sqlmodel: Any): # clear_sqlmodel still useful for DB state
|
||||
# If module.main() is responsible for creating data and potentially tables, call it.
|
||||
# The fixture get_module now ensures the engine is set and tables are created if models are defined.
|
||||
# If main() also sets up engine/tables, ensure it's idempotent or adjust.
|
||||
# Typically, main() in these tutorials contains the primary logic to be tested (e.g., data insertion).
|
||||
module.main() # This should execute the tutorial's data insertion logic
|
||||
|
||||
with Session(module.engine) as session:
|
||||
heroes = session.exec(select(module.Hero)).all()
|
||||
|
||||
mod.sqlite_url = "sqlite://"
|
||||
mod.engine = create_engine(mod.sqlite_url)
|
||||
mod.main()
|
||||
with Session(mod.engine) as session:
|
||||
heroes = session.exec(select(mod.Hero)).all()
|
||||
heroes_by_name = {hero.name: hero for hero in heroes}
|
||||
deadpond = heroes_by_name["Deadpond"]
|
||||
spider_boy = heroes_by_name["Spider-Boy"]
|
||||
rusty_man = heroes_by_name["Rusty-Man"]
|
||||
|
||||
assert deadpond.name == "Deadpond"
|
||||
assert deadpond.age is None
|
||||
assert deadpond.id is not None
|
||||
assert deadpond.secret_name == "Dive Wilson"
|
||||
|
||||
assert spider_boy.name == "Spider-Boy"
|
||||
assert spider_boy.age is None
|
||||
assert spider_boy.id is not None
|
||||
assert spider_boy.secret_name == "Pedro Parqueador"
|
||||
|
||||
assert rusty_man.name == "Rusty-Man"
|
||||
assert rusty_man.age == 48
|
||||
assert rusty_man.id is not None
|
||||
|
Reference in New Issue
Block a user