Skip to content
Snippets Groups Projects
Commit 3a79ce82 authored by Françoise Conil's avatar Françoise Conil
Browse files

Code de la présentation pytest

parents
No related branches found
No related tags found
No related merge requests found
Showing
with 651 additions and 0 deletions
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
# Testing tools
.pytest_cache/
# Distribution / packaging
./build/
dist/
# Environments
.venv
venv/
# IDE specific
*~
.vscode/settings.json
# OS specific
*.DS_Store
pytest
pip-tools
ipython
black
flake8
#
# This file is autogenerated by pip-compile with Python 3.10
# by the following command:
#
# pip-compile --resolver=backtracking requirements.in
#
asttokens==2.2.1
# via stack-data
backcall==0.2.0
# via ipython
black==23.3.0
# via -r requirements.in
build==0.10.0
# via pip-tools
click==8.1.3
# via
# black
# pip-tools
decorator==5.1.1
# via ipython
exceptiongroup==1.1.1
# via pytest
executing==1.2.0
# via stack-data
flake8==6.0.0
# via -r requirements.in
iniconfig==2.0.0
# via pytest
ipython==8.14.0
# via -r requirements.in
jedi==0.18.2
# via ipython
matplotlib-inline==0.1.6
# via ipython
mccabe==0.7.0
# via flake8
mypy-extensions==1.0.0
# via black
packaging==23.1
# via
# black
# build
# pytest
parso==0.8.3
# via jedi
pathspec==0.11.1
# via black
pexpect==4.8.0
# via ipython
pickleshare==0.7.5
# via ipython
pip-tools==6.13.0
# via -r requirements.in
platformdirs==3.8.0
# via black
pluggy==1.2.0
# via pytest
prompt-toolkit==3.0.38
# via ipython
ptyprocess==0.7.0
# via pexpect
pure-eval==0.2.2
# via stack-data
pycodestyle==2.10.0
# via flake8
pyflakes==3.0.1
# via flake8
pygments==2.15.1
# via ipython
pyproject-hooks==1.0.0
# via build
pytest==7.4.0
# via -r requirements.in
six==1.16.0
# via asttokens
stack-data==0.6.2
# via ipython
tomli==2.0.1
# via
# black
# build
# pyproject-hooks
# pytest
traitlets==5.9.0
# via
# ipython
# matplotlib-inline
wcwidth==0.2.6
# via prompt-toolkit
wheel==0.40.0
# via pip-tools
# The following packages are considered to be unsafe in a requirements file:
# pip
# setuptools
"""Simplest pytest test
https://docs.pytest.org/en/stable/getting-started.html#install-pytest
"""
def add(n):
return n + 1
def test_add_one():
# Expect a function adding 1 to the number passed
assert add(3) == 4
def test_add_two():
# Expect a function adding 2 to the number passed
assert add(3) == 5
if __name__ == "__main__":
test_add_one()
test_add_two()
import pytest
def get_index(list_dict, key, value):
"""helper to get index of a key in a json file"""
for i in range(len(list_dict)):
if list_dict[i][key] == value:
return i
@pytest.fixture()
def list_sports():
return [
{"sport": "swimming", "nb_videos": 100},
{"sport": "ping pong", "nb_videos": 50},
{"sport": "synchronized swimming", "nb_videos": 15},
]
def test_get_index(list_sports):
index = get_index(list_sports, "sport", "ping pong")
assert index == 1
from pathlib import Path
import sqlite3
import pytest
from tempfile import TemporaryDirectory
def get_nb_sport(conn):
req = conn.execute("SELECT count(*) FROM sports")
res = req.fetchone()
return res if res is None else res[0]
@pytest.fixture()
def sport_db():
with TemporaryDirectory() as db_dir:
db_path = Path(db_dir) / "sports.db"
conn = sqlite3.connect(db_path)
# cur = conn.cursor()
conn.execute(
"CREATE TABLE sports(id integer primary key autoincrement, sport, nb_videos integer)"
)
yield conn
conn.close()
def test_empty_db(sport_db):
nb_sports = get_nb_sport(sport_db)
assert nb_sports == 0
"""
Demander des informations sur la notion de curseur.
https://docs.python.org/3/library/sqlite3.html
Pour afficher le chemin de la bd associé à une connexion
for id_, name, filename in sport_db.execute("PRAGMA database_list"): print (id_, name, filename)
https://stackoverflow.com/questions/13912731/python-sqlite3-get-sqlite-connection-path
"""
from pathlib import Path
import sqlite3
import pytest
from tempfile import TemporaryDirectory
def get_nb_sport(conn):
req = conn.execute("SELECT count(*) FROM sports")
res = req.fetchone()
return res if res is None else res[0]
def get_index(conn, value):
req = conn.execute("SELECT id FROM sports WHERE sport = ?", (value,))
res = req.fetchone()
return res if res is None else res[0]
@pytest.fixture(scope="module")
def sport_db():
with TemporaryDirectory() as db_dir:
db_path = Path(db_dir) / "sports.db"
conn = sqlite3.connect(db_path)
# cur = conn.cursor()
conn.execute(
"CREATE TABLE sports(id integer primary key autoincrement, sport, nb_videos integer)"
)
yield conn
conn.close()
@pytest.fixture(scope="function")
def sport_not_empty_db(sport_db):
data = [("swimming", 100), ("ping pong", 50), ("synchronized swimming", 15)]
sport_db.executemany("INSERT INTO sports (sport, nb_videos) VALUES (?, ?)", data)
sport_db.commit()
yield sport_db
sport_db.execute("DELETE FROM sports")
def test_get_index(sport_not_empty_db):
index = get_index(sport_not_empty_db, "ping pong")
assert index == 2
def test_empty_db(sport_db):
nb_sports = get_nb_sport(sport_db)
assert nb_sports == 0
from pathlib import Path
import sqlite3
import pytest
from tempfile import TemporaryDirectory
@pytest.fixture(scope="session")
def sport_db():
with TemporaryDirectory() as db_dir:
db_path = Path(db_dir) / "sports.db"
conn = sqlite3.connect(db_path)
# cur = conn.cursor()
conn.execute(
"CREATE TABLE sports(id integer primary key autoincrement, sport, nb_videos integer)"
)
yield conn
conn.close()
@pytest.fixture(scope="function")
def sport_not_empty_db(sport_db):
data = [("swimming", 100), ("ping pong", 50), ("synchronized swimming", 15)]
sport_db.executemany("INSERT INTO sports (sport, nb_videos) VALUES (?, ?)", data)
sport_db.commit()
yield sport_db
sport_db.execute("DELETE FROM sports")
@pytest.fixture()
def sports_list():
return [
{"sport": "swimming", "nb_videos": 100},
{"sport": "ping pong", "nb_videos": 50},
{"sport": "synchronized swimming", "nb_videos": 15},
]
"""
Demander des informations sur la notion de curseur.
https://docs.python.org/3/library/sqlite3.html
Pour afficher le chemin de la bd associé à une connexion
for id_, name, filename in sport_db.execute("PRAGMA database_list"): print (id_, name, filename)
https://stackoverflow.com/questions/13912731/python-sqlite3-get-sqlite-connection-path
"""
def get_nb_sport(conn):
req = conn.execute("SELECT count(*) FROM sports")
res = req.fetchone()
return res if res is None else res[0]
def get_index(conn, value):
req = conn.execute("SELECT id FROM sports WHERE sport = ?", (value,))
res = req.fetchone()
return res if res is None else res[0]
def add_sport(conn, sport, nb_videos):
conn.execute(
"INSERT INTO sports (sport, nb_videos) VALUES (?, ?)", (sport, nb_videos)
)
conn.commit()
def test_get_index(sport_not_empty_db):
index = get_index(sport_not_empty_db, "ping pong")
assert index == 2
def test_empty_db(sport_db):
nb_sports = get_nb_sport(sport_db)
assert nb_sports == 0
def test_add_sport(sport_db, sports_list):
for sport in sports_list:
add_sport(sport_db, sport["sport"], sport["nb_videos"])
assert get_nb_sport(sport_db) == 3
import time
import pytest
def get_nb_frames(video):
time.sleep(2)
return 100
def extract_swimmer(video):
time.sleep(2)
return {"x": 12, "y": 34, "pos": 5, "meta_1": "val_1"}
def get_video_duration(video):
return 20
@pytest.mark.slow
def test_get_nb_frames():
video = "sample/video.mp4"
nb_frames = get_nb_frames(video)
assert nb_frames == 100
@pytest.mark.slow
def test_extract_swimmer():
video = "sample/video.mp4"
swimmer = extract_swimmer(video)
assert swimmer == {"x": 12, "y": 34, "pos": 5, "meta_1": "val_1"}
def test_get_video_duration():
video = "sample/video.mp4"
duration = get_video_duration(video)
assert duration == 20
import os
import pytest
def sound_gap_measure(video_ref, video_new):
# Function that is not ready yet
return 0
@pytest.mark.skip(reason="Function is not coded yet")
def test_no_sound_gap():
# GIVEN a reference video, compute the gap with a given video using sound
video_ref = "sample/video_ref.mp4"
video_new = "sample/video_new.mp4"
# WHEN we compute the gap between the video using the starter sound
gap = sound_gap_measure(video_ref, video_new)
# THEN there should be no difference
assert gap == 0
def extract_frame(video, frame):
# Fake function
pass
@pytest.mark.skipif(os.cpu_count() < 8, reason="Your computer is not powerfull enough")
def test_extract_frame(tmp_path):
# GIVEN a video
video = "sample/video.mp4"
frame = "sample/frame.jpg"
# WHEN we extract a frame from the video
extract_frame(video, frame)
# THEN the frame should exist after the extraction
assert frame.exists()
import sys
import pytest
def get_windows_version():
return 10
def get_system():
return sys.platform()
@pytest.mark.xfail(reason="I do not have a windows system")
def test_run_on_windows():
platform = get_system()
assert platform == "win32"
@pytest.mark.xfail(reason="We should required Windows 11")
def test_windows_version():
version = get_windows_version()
assert version >= 10
@pytest.mark.xfail(reason="We should required Windows 11", strict=True)
def test_windows_version_strict():
version = get_windows_version()
assert version >= 10
import pytest
@pytest.fixture(
params=[
"samples/video1.mp4",
"samples/video2.mp4",
"samples/video3.mp4",
]
)
def video_input(request):
return request.param
@pytest.fixture(
params=[
{"video": "samples/video1.mp4", "duration": 100, "frames": 2400},
{"video": "samples/video2.mp4", "duration": 15, "frames": 360},
{"video": "samples/video3.mp4", "duration": 5, "frames": 120},
]
)
def video_frames_input(request):
return request.param
@pytest.fixture(
params=[
{"video": "samples/video1.mp4", "duration": 100, "frames": 2400},
{"video": "samples/video2.mp4", "duration": 15, "frames": 360},
{"video": "samples/video3.mp4", "duration": 5, "frames": 120},
],
ids=["video1_d-100_f-2400", "video2_d-15_f-360", "video3_d-5_f-120"],
)
def video_frames_input_with_ids(request):
return request.param
def pytest_addoption(parser):
parser.addoption(
"--video_path",
action="append",
default=[],
help="list of video path to pass to test functions",
)
def get_video_duration(video):
return 20
def test_get_video_duration(video_input):
video = video_input
assert get_video_duration(video) == 20
def get_nb_frames(video, duration):
return duration * 24
def test_get_nb_frames(video_frames_input):
nbf = get_nb_frames(video_frames_input["video"], video_frames_input["duration"])
assert nbf == video_frames_input["frames"]
def test_get_nb_frames_with_ids(video_frames_input_with_ids):
nbf = get_nb_frames(
video_frames_input_with_ids["video"], video_frames_input_with_ids["duration"]
)
assert nbf == video_frames_input_with_ids["frames"]
"""
pytest_generate_tests ne fonctionne pas si la fixture video_input est définie
dans conftest.py ou dans le fichier courant (test_hook.py)
$ pytest -v --no-header --video_path="samples/video4.mp4" tests/ex6/test_hook.py
============================================================================ test session starts =============================================================================
collected 0 items / 1 error
=================================================================================== ERRORS ===================================================================================
_____________________________________________________________________ ERROR collecting ex6/test_hook.py ______________________________________________________________________
.venv/lib/python3.10/site-packages/_pytest/runner.py:341: in from_call
result: Optional[TResult] = func()
.venv/lib/python3.10/site-packages/_pytest/runner.py:372: in <lambda>
call = CallInfo.from_call(lambda: list(collector.collect()), "collect")
.venv/lib/python3.10/site-packages/_pytest/python.py:534: in collect
return super().collect()
.venv/lib/python3.10/site-packages/_pytest/python.py:455: in collect
res = ihook.pytest_pycollect_makeitem(
.venv/lib/python3.10/site-packages/pluggy/_hooks.py:433: in __call__
return self._hookexec(self.name, self._hookimpls, kwargs, firstresult)
.venv/lib/python3.10/site-packages/pluggy/_manager.py:112: in _hookexec
return self._inner_hookexec(hook_name, methods, kwargs, firstresult)
.venv/lib/python3.10/site-packages/_pytest/python.py:271: in pytest_pycollect_makeitem
return list(collector._genfunctions(name, obj))
.venv/lib/python3.10/site-packages/_pytest/python.py:498: in _genfunctions
self.ihook.pytest_generate_tests.call_extra(methods, dict(metafunc=metafunc))
.venv/lib/python3.10/site-packages/pluggy/_hooks.py:489: in call_extra
return self._hookexec(self.name, hookimpls, kwargs, firstresult)
.venv/lib/python3.10/site-packages/pluggy/_manager.py:112: in _hookexec
return self._inner_hookexec(hook_name, methods, kwargs, firstresult)
.venv/lib/python3.10/site-packages/_pytest/fixtures.py:1570: in pytest_generate_tests
metafunc.parametrize(
.venv/lib/python3.10/site-packages/_pytest/python.py:1347: in parametrize
newcallspec = callspec.setmulti(
.venv/lib/python3.10/site-packages/_pytest/python.py:1152: in setmulti
raise ValueError(f"duplicate {arg!r}")
E ValueError: duplicate 'video_input'
========================================================================== short test summary info ===========================================================================
ERROR tests/ex6/test_hook.py - ValueError: duplicate 'video_input'
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Interrupted: 1 error during collection !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
============================================================================== 1 error in 0.45s ==============================================================================
Conclusion : les fixtures n'ont pas besoin d'être dans conftest.py pour être collectées. A étudier !!!!
"""
def get_video_duration(video):
return 20
def pytest_generate_tests(metafunc):
if "video_input" in metafunc.fixturenames:
metafunc.parametrize("video_input", metafunc.config.getoption("video_path"))
def test_get_dynamic_video_duration(video_input):
video = video_input
assert get_video_duration(video) == 20
import pytest
def get_nb_frames(video, duration):
return duration * 24
@pytest.mark.parametrize(
"video, duration, nb_frames",
[
("samples/video1.mp4", 100, 2400),
("samples/video2.mp4", 15, 360),
("samples/video3.mp4", 5, 120),
],
)
def test_get_nb_frames(video, duration, nb_frames):
nbf = get_nb_frames(video, duration)
assert nbf == nb_frames
import pytest
def get_nb_frames(video, duration):
return duration * 24
@pytest.mark.parametrize(
["video", "duration", "nb_frames"],
[
["samples/video1.mp4", 100, 2400],
["samples/video2.mp4", 15, 360],
["samples/video3.mp4", 5, 120],
],
)
def test_get_nb_frames(video, duration, nb_frames):
nbf = get_nb_frames(video, duration)
assert nbf == nb_frames
import pytest
@pytest.fixture
def video_input(request):
return request.param
def pytest_addoption(parser):
parser.addoption(
"--video_path",
action="append",
default=[],
help="list of video path to pass to test functions",
)
"""
pytest_generate_tests ne fonctionne pas si la fixture video_input est définie
dans conftest.py ou dans le fichier courant (test_hook.py)
https://github.com/pytest-dev/pytest/issues/2726
$ pytest -v --no-header --video_path="samples/video4.mp4" tests/ex6/test_hook.py
"""
import pytest
def get_video_duration(video):
return 20
def pytest_generate_tests(metafunc):
if "video_input" in metafunc.fixturenames:
metafunc.parametrize("video_input", metafunc.config.getoption("video_path"))
@pytest.mark.parametrize("video_input", ["samples/video1.mp4", "samples/video2.mp4", "samples/video3.mp4"], indirect=True)
def test_get_dynamic_video_duration(video_input):
video = video_input
assert get_video_duration(video) == 20
def pytest_addoption(parser):
parser.addoption(
"--video_path",
action="append",
default=[],
help="list of video path to pass to test functions",
)
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment