# Pytest Fixtures ```python= ######### Main library ############ import pytest from flask.testing import FlaskClient from dotenv import load_dotenv # For DB, to allow the model to be test without real db import sqlalchemy from sqlalchemy_utils import create_database, database_exists from flask_migrate import Migrate, upgrade, stamp # Import all related model and configuration be test from apps import config from apps.server import create_app from apps.model.abc import db from apps.model.abc import Base # Load test specicif config load_dotenv() # Apply latest migration migrate = Migrate() ``` >*Mostly, importing the config for real deployment is the best option, since it will make sure test the config against real deployment.* > Except for some config, (example, Debuging mode, etc) ----- ### Setup Fixtures (required) - What usually set here? - Setup header (Authentication) - Create user / group or any default data ```python= @pytest.fixture def jwt_app(): app = create_app() app.config["TESTING"] = True app.test_client_class = JWTClient # Create tables in database with app.app_context(): engine = sqlalchemy.create_engine(config.DB_URI) db.init_app(app) migrate.init_app(app, db) if not database_exists(engine.url): create_database(engine.url) # init("/home/apps/migrations") upgrade("/home/apps/migrations", "head") yield app # remove tables in database with app.app_context(): engine = db.get_engine(bind=None) Base.metadata.drop_all(engine) stamp("/home/apps/migrations", "base") db.drop_all() @pytest.fixture def jwt_client(jwt_app): return jwt_app.test_client() @pytest.fixture def jwt_context(jwt_app): return jwt_app.app_context() ``` ### Writing test case - Example to access db while test ```python= def test_get_get_username(jwt_client, jwt_context): # noqa: F811 with jwt_context: user_data = User("joe@example.fr", "super-secret-password") db.session.add(user_data) db.session.commit() rsp = jwt_client.get(f"/user/{user_data.id}") data = rsp.json assert rsp.status_code == 200 assert data["email"] == "joe@example.fr" ``` - Example just access endpoint (Fill in the fixtures) ```python= # Edit the fixtures # In the test case def test_get_get_username(jwt_client, jwt_context): # noqa: F811 rsp = jwt_client.get(f"/user/1") data = rsp.json assert rsp.status_code == 200 assert data["email"] == "joe@example.fr" ``` - Example using reusable function ```python= def create_user(jwt_context): with jwt_context: user_data = User("joe@example.fr", "super-secret-password") db.session.add(user_data) db.session.commit() return user_data.id def test_get_get_username_form_2(jwt_client, jwt_context): # noqa: F811 user = create_user(jwt_context) rsp = jwt_client.get(f"/user/{user.id}") data = rsp.json assert rsp.status_code == 200 assert data["email"] == "joe@example.fr" ``` - Make sure to test as much as posibilities can happen - How if the endpoint receive a script ? - How if the payload is not correct - How if the data not found on server - etc..... ## Mock Test - Assume we have endpoint which need to hit another service ```python= class ExampleMock(Resource): def get(self): response_example = requests.get( "https://random-data-api.com/api/v2/users?size=2&response_type=json" ) return jsonify(response_example.json()) ``` - In test, we can test with / without mocker ```python= def test_mock_without_mock(jwt_client: FlaskClient): data = {"A": "B"} rsp = jwt_client.get(f"/mocks") assert rsp.json != data def test_mock_with_mocker(jwt_client: FlaskClient): with requests_mock.Mocker() as mocker: data = {"A": "B"} mocker.get( "https://random-data-api.com/api/v2/users?size=2&response_type=json", json=data, status_code=200, ) rsp = jwt_client.get(f"/mocks") assert rsp.json == data ``` - We can mock function, object, or many things, to encapsulate the test case