Je souhaite exécuter facilement un test unitaire d'une application Python à l'aide d'une base de données avec pytest sans être affecté par l'environnement. (Ceux qui démarrent en tant que démon au lieu de fichiers tels que SQLite3)
Exemple de code: https://github.com/hkato/pytest-docker-mysql-example
Lancez MySQL à partir de pytest sur Docker, entrez le schéma et les données de test, et exécutez le test. Si vous définissez docker-compose et que vous prenez en charge SQL lié à docker-entrypoint-initdb.d, il devrait en être de même pour les autres bases de données telles que PostgreSQL. (Le mécanisme d'initialisation dans docker-entrypoint-initdb.d devrait être le même pour les conteneurs officiels MySQL / PostgreSQL, mais je ne sais rien d'autre)
Concernant pytest, j'ai démarré Docker et regardé le plug-in qui gère la base de données, mais pytest-docker est le statut de maintenance et mon utilisation / environnement Ça a l'air bien pour. pytest-dotenv a été utilisé par Docker et pytest pour décrire les variables d'environnement dans les fichiers .env et les rendre communes.
À la suite de considérations autres que pytest-docker
Après tout, pytest-docker semble être le meilleur car il peut utiliser le conteneur de l'application Web comme décrit dans le document officiel, et il peut être utilisé à des fins générales quelle que soit la base de données ([Démarrer le conteneur MinIO et remplacer AWS S3](https :: //qiita.com/hkato/items/89e436300c50c46624b9) Je pense le faire aussi).
.
├── src #Code d'application
│ └── *.py
├── tests #Code de test
│ ├── conftest.py
│ └── test_*.py
├── initdb.d #Schéma de base de données et données de test, etc.
│ ├── *.sql
│ └── *.sh
├── pytest.ini #paramètres pytest
├── .env #Paramètres des variables d'environnement
└── docker-compose.yml #Paramètres de Docker
conftest.py
Par défaut, pytest-docker référence docker-compose.yml
sous tests /
. En définissant directement sous le projet (spécifiez un autre répertoire ou nom de fichier dans l'exemple dans README.md de pytest-docker), dans le cas des applications Web etc., exécutez la base de données avec docker-compose up -d
Vous pouvez exécuter et déboguer un serveur d'applications Web avec Gunicorn, uWSGI, Uvicorn, etc. (j'exclus cela car ce n'est pas l'essence de cette fois).
La documentation de pytest-docker le décrit comme un exemple de lancement d'un conteneur d'API REST httpbin et d'attente de 200 réponses du port 80. Dans le cas de MySQL, il a été décidé que la connexion était établie avec PyMySQL comme indiqué ci-dessous et aucune exception n'a été renvoyée, c'est-à-dire que le conteneur Docker a été démarré et que les données initiales ont été entrées.
def is_database_ready(docker_ip):
try:
pymysql.connect(
host=docker_ip,
user=os.getenv('MYSQL_USER', ''),
password=os.getenv('MYSQL_PASSWORD', ''),
db=os.getenv('MYSQL_DATABASE')
)
return True
except:
return False
Attendez ce qui précède avec un délai de 30 secondes dans un cycle de 0,1 seconde.
@pytest.fixture(scope="session")
def database_service(docker_ip, docker_services):
docker_services.wait_until_responsive(
timeout=30.0, pause=0.1, check=lambda: is_database_ready(docker_ip)
)
return
Configuration initiale de l'environnement Python
$ #En fonctionnement réel, il peut être préférable d'utiliser Pipenv ou Poetry pour l'environnement de test et l'environnement d'exécution.
$ python -m venv .venv
$ source .venv/bin/activate
$ pip install -r requirements.txt
Paramètres des variables d'environnement
$ cat << 'EOF' > .env
MYSQL_ROOT_PASSWORD='p@ssw0rd'
MYSQL_DATABASE='mydb'
MYSQL_USER='foo'
MYSQL_PASSWORD='pa$$Word'
EOF
Lorsque le test est exécuté, le conteneur Docker est démarré par Fixture, et le test unitaire réel est exécuté après que les scripts SQL et shell soient appliqués par le mécanisme de docker-entrypoint-initdb.d dans le conteneur.
$ pytest
============================= test session starts ==============================
platform darwin -- Python 3.8.6, pytest-6.1.2, py-1.9.0, pluggy-0.13.1 -- /Users/username/tmp/.venv/bin/python
cachedir: .pytest_cache
rootdir: /Users/username/tmp, configfile: pytest.ini
plugins: dotenv-0.5.2, cov-2.10.1, docker-0.10.1
collected 1 item
tests/test_users.py::test_get_name_by_id PASSED [100%]
---------- coverage: platform darwin, python 3.8.6-final-0 -----------
Name Stmts Miss Cover
--------------------------------
src/app.py 8 0 100%
============================== 1 passed in 16.35s ==============================
--pytest-docker est pratique car vous pouvez lancer des services qui dépendent de tests, pas seulement de bases de données, avec Docker. --Il peut être bon de changer l'emplacement de docker-compose.yml de tests / directement sous le projet. Peut également être utilisé pour le débogage normal
Recommended Posts