# 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