marintosti12 commited on
Commit
f2b90ca
·
1 Parent(s): 5396b54

fix(tests) fix some test

Browse files
poetry.lock CHANGED
@@ -1642,6 +1642,17 @@ perf = ["ipython"]
1642
  test = ["flufl.flake8", "importlib_resources (>=1.3)", "jaraco.test (>=5.4)", "packaging", "pyfakefs", "pytest (>=6,!=8.1.*)", "pytest-perf (>=0.9.2)"]
1643
  type = ["pytest-mypy"]
1644
 
 
 
 
 
 
 
 
 
 
 
 
1645
  [[package]]
1646
  name = "ipykernel"
1647
  version = "6.31.0"
@@ -3581,6 +3592,21 @@ files = [
3581
  packaging = "*"
3582
  tenacity = ">=6.2.0"
3583
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3584
  [[package]]
3585
  name = "polyfactory"
3586
  version = "3.0.0"
@@ -4100,6 +4126,27 @@ files = [
4100
  [package.extras]
4101
  diagrams = ["jinja2", "railroad-diagrams"]
4102
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4103
  [[package]]
4104
  name = "python-dateutil"
4105
  version = "2.9.0.post0"
@@ -6074,4 +6121,4 @@ type = ["pytest-mypy"]
6074
  [metadata]
6075
  lock-version = "2.0"
6076
  python-versions = "^3.12"
6077
- content-hash = "b8dab684f91fefcaf3dc9b440bcac2b4e61e555b39aa6a961b3bd873d58f57ef"
 
1642
  test = ["flufl.flake8", "importlib_resources (>=1.3)", "jaraco.test (>=5.4)", "packaging", "pyfakefs", "pytest (>=6,!=8.1.*)", "pytest-perf (>=0.9.2)"]
1643
  type = ["pytest-mypy"]
1644
 
1645
+ [[package]]
1646
+ name = "iniconfig"
1647
+ version = "2.3.0"
1648
+ description = "brain-dead simple config-ini parsing"
1649
+ optional = false
1650
+ python-versions = ">=3.10"
1651
+ files = [
1652
+ {file = "iniconfig-2.3.0-py3-none-any.whl", hash = "sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12"},
1653
+ {file = "iniconfig-2.3.0.tar.gz", hash = "sha256:c76315c77db068650d49c5b56314774a7804df16fee4402c1f19d6d15d8c4730"},
1654
+ ]
1655
+
1656
  [[package]]
1657
  name = "ipykernel"
1658
  version = "6.31.0"
 
3592
  packaging = "*"
3593
  tenacity = ">=6.2.0"
3594
 
3595
+ [[package]]
3596
+ name = "pluggy"
3597
+ version = "1.6.0"
3598
+ description = "plugin and hook calling mechanisms for python"
3599
+ optional = false
3600
+ python-versions = ">=3.9"
3601
+ files = [
3602
+ {file = "pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746"},
3603
+ {file = "pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3"},
3604
+ ]
3605
+
3606
+ [package.extras]
3607
+ dev = ["pre-commit", "tox"]
3608
+ testing = ["coverage", "pytest", "pytest-benchmark"]
3609
+
3610
  [[package]]
3611
  name = "polyfactory"
3612
  version = "3.0.0"
 
4126
  [package.extras]
4127
  diagrams = ["jinja2", "railroad-diagrams"]
4128
 
4129
+ [[package]]
4130
+ name = "pytest"
4131
+ version = "9.0.1"
4132
+ description = "pytest: simple powerful testing with Python"
4133
+ optional = false
4134
+ python-versions = ">=3.10"
4135
+ files = [
4136
+ {file = "pytest-9.0.1-py3-none-any.whl", hash = "sha256:67be0030d194df2dfa7b556f2e56fb3c3315bd5c8822c6951162b92b32ce7dad"},
4137
+ {file = "pytest-9.0.1.tar.gz", hash = "sha256:3e9c069ea73583e255c3b21cf46b8d3c56f6e3a1a8f6da94ccb0fcf57b9d73c8"},
4138
+ ]
4139
+
4140
+ [package.dependencies]
4141
+ colorama = {version = ">=0.4", markers = "sys_platform == \"win32\""}
4142
+ iniconfig = ">=1.0.1"
4143
+ packaging = ">=22"
4144
+ pluggy = ">=1.5,<2"
4145
+ pygments = ">=2.7.2"
4146
+
4147
+ [package.extras]
4148
+ dev = ["argcomplete", "attrs (>=19.2)", "hypothesis (>=3.56)", "mock", "requests", "setuptools", "xmlschema"]
4149
+
4150
  [[package]]
4151
  name = "python-dateutil"
4152
  version = "2.9.0.post0"
 
6121
  [metadata]
6122
  lock-version = "2.0"
6123
  python-versions = "^3.12"
6124
+ content-hash = "b9fd38929cdea119f903a516c304ae653c247858d0543101d5029885dfa76c89"
pyproject.toml CHANGED
@@ -28,6 +28,7 @@ psycopg = {extras = ["binary"], version = "^3.2.12"}
28
  huggingface-hub = "^1.1.2"
29
  dotenv = "^0.9.9"
30
  evidently = "^0.7.16"
 
31
 
32
 
33
  [tool.poetry.group.dev.dependencies]
@@ -39,3 +40,7 @@ gprof2dot = "^2025.4.14"
39
  requires = ["poetry-core"]
40
  build-backend = "poetry.core.masonry.api"
41
 
 
 
 
 
 
28
  huggingface-hub = "^1.1.2"
29
  dotenv = "^0.9.9"
30
  evidently = "^0.7.16"
31
+ pytest = "^9.0.1"
32
 
33
 
34
  [tool.poetry.group.dev.dependencies]
 
40
  requires = ["poetry-core"]
41
  build-backend = "poetry.core.masonry.api"
42
 
43
+
44
+ [tool.pytest.ini_options]
45
+ pythonpath = ["."]
46
+ testpaths = ["tests"]
src/__init__.py ADDED
File without changes
src/main.py CHANGED
@@ -2,8 +2,8 @@
2
  from fastapi import FastAPI
3
 
4
 
5
- from controllers.home_controller import router as ml_home_router
6
- from controllers.predict_controller import router as predict_router
7
 
8
 
9
  app = FastAPI(title="ML API",
 
2
  from fastapi import FastAPI
3
 
4
 
5
+ from src.controllers.home_controller import router as ml_home_router
6
+ from src.controllers.predict_controller import router as predict_router
7
 
8
 
9
  app = FastAPI(title="ML API",
tests/functional/test_home.py CHANGED
@@ -1,31 +1,40 @@
 
 
 
1
  from fastapi.testclient import TestClient
2
  from sqlalchemy import create_engine
3
  from sqlalchemy.orm import sessionmaker
4
 
5
- from main import app
6
  from config.db import get_db
7
-
8
  from models.ml import MLModel
9
 
10
- import uuid
11
- from datetime import datetime, timezone
12
-
13
 
14
- def test_list_models_simple(tmp_path):
 
15
  db_path = tmp_path / "testing.db"
16
  engine = create_engine(
17
  f"sqlite:///{db_path}",
18
  connect_args={"check_same_thread": False},
19
  future=True,
20
  )
21
- SQLSession = sessionmaker(bind=engine, autoflush=False, autocommit=False, future=True)
 
 
 
 
 
22
 
23
- MLModel.metadata.create_all(engine)
24
 
 
25
  session = SQLSession()
26
 
27
  def get_db_override():
28
- return session
 
 
 
29
 
30
  app.dependency_overrides[get_db] = get_db_override
31
 
@@ -48,7 +57,7 @@ def test_list_models_simple(tmp_path):
48
  created_at=created,
49
  is_active=True,
50
  ),
51
- MLModel(
52
  id=uuid.UUID("5b1c7b3a-0000-4000-8000-000000000003"),
53
  name="logistic_regression",
54
  description="Logistic Regression",
@@ -61,32 +70,10 @@ def test_list_models_simple(tmp_path):
61
 
62
  resp = client.get("/")
63
 
64
-
65
  app.dependency_overrides.clear()
66
  session.close()
67
 
68
  assert resp.status_code == 200
69
  data = resp.json()
70
  names = {row["name"] for row in data}
71
- assert names == {"baseline", "best_model", 'logistic_regression'}
72
-
73
-
74
- def test_list_models_returns_500_when_db_fails():
75
- class BrokenSession:
76
- def query(self, *a, **kw):
77
- raise RuntimeError("DB is down")
78
-
79
- def get_db_override():
80
- yield BrokenSession()
81
-
82
- app.dependency_overrides[get_db] = get_db_override
83
- client = TestClient(app, raise_server_exceptions=False)
84
-
85
- resp = client.get("/")
86
-
87
- app.dependency_overrides.clear()
88
-
89
- assert resp.status_code == 500
90
- body = resp.json()
91
- assert "DB is down" in body["detail"]
92
-
 
1
+ from datetime import datetime, timezone
2
+ import uuid
3
+
4
  from fastapi.testclient import TestClient
5
  from sqlalchemy import create_engine
6
  from sqlalchemy.orm import sessionmaker
7
 
8
+ from src.main import app
9
  from config.db import get_db
 
10
  from models.ml import MLModel
11
 
 
 
 
12
 
13
+ def test_list_ml_models_simple(tmp_path):
14
+ # Création d'une base SQLite temporaire
15
  db_path = tmp_path / "testing.db"
16
  engine = create_engine(
17
  f"sqlite:///{db_path}",
18
  connect_args={"check_same_thread": False},
19
  future=True,
20
  )
21
+ SQLSession = sessionmaker(
22
+ bind=engine,
23
+ autoflush=False,
24
+ autocommit=False,
25
+ future=True,
26
+ )
27
 
28
+ MLModel.__table__.create(bind=engine)
29
 
30
+ # Session dédiée au test
31
  session = SQLSession()
32
 
33
  def get_db_override():
34
+ try:
35
+ yield session
36
+ finally:
37
+ pass
38
 
39
  app.dependency_overrides[get_db] = get_db_override
40
 
 
57
  created_at=created,
58
  is_active=True,
59
  ),
60
+ MLModel(
61
  id=uuid.UUID("5b1c7b3a-0000-4000-8000-000000000003"),
62
  name="logistic_regression",
63
  description="Logistic Regression",
 
70
 
71
  resp = client.get("/")
72
 
 
73
  app.dependency_overrides.clear()
74
  session.close()
75
 
76
  assert resp.status_code == 200
77
  data = resp.json()
78
  names = {row["name"] for row in data}
79
+ assert names == {"baseline", "best_model", "logistic_regression"}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
tests/functional/test_predict.py DELETED
@@ -1,364 +0,0 @@
1
- from fastapi.testclient import TestClient
2
- from sqlalchemy import create_engine
3
- from sqlalchemy.orm import sessionmaker
4
-
5
- from main import app
6
- from config.db import get_db
7
-
8
- from models.ml import MLModel
9
- from models.ml_inputs import MLInput
10
- from models.ml_output import MLOutput
11
-
12
- import uuid
13
- from datetime import datetime, timezone
14
-
15
-
16
- def test_simple_predict(tmp_path):
17
- db_path = tmp_path / "testing.db"
18
- engine = create_engine(
19
- f"sqlite:///{db_path}",
20
- connect_args={"check_same_thread": False},
21
- future=True,
22
- )
23
- SQLSession = sessionmaker(bind=engine, autoflush=False, autocommit=False, future=True)
24
-
25
- MLModel.metadata.create_all(engine)
26
- MLInput.metadata.create_all(engine)
27
- MLOutput.metadata.create_all(engine)
28
-
29
- session = SQLSession()
30
-
31
- def get_db_override():
32
- return session
33
-
34
-
35
- app.dependency_overrides[get_db] = get_db_override
36
-
37
- client = TestClient(app, raise_server_exceptions=False)
38
-
39
- created = datetime(2025, 9, 15, 10, 11, 3, 950802, tzinfo=timezone.utc)
40
- session.add_all(
41
- [
42
- MLModel(
43
- id=uuid.UUID("5b1c7b3a-0000-4000-8000-000000000001"),
44
- name="baseline",
45
- description="Baseline model",
46
- created_at=created,
47
- is_active=True,
48
- ),
49
- MLModel(
50
- id=uuid.UUID("5b1c7b3a-0000-4000-8000-000000000002"),
51
- name="best_model",
52
- description="XGB v1",
53
- created_at=created,
54
- is_active=True,
55
- ),
56
- MLModel(
57
- id=uuid.UUID("5b1c7b3a-0000-4000-8000-000000000003"),
58
- name="logistic_regression",
59
- description="Logistic Regression",
60
- created_at=created,
61
- is_active=True,
62
- ),
63
- ]
64
- )
65
- session.commit()
66
-
67
-
68
- payload = {
69
- "model_name": "best_model",
70
- "inputs": [{
71
- "id_employee": 123,
72
- "age": 35,
73
- "genre": "Homme",
74
- "revenu_mensuel": 4200,
75
- "statut_marital": "Célibataire",
76
- "departement": "Ventes",
77
- "poste": "Commercial",
78
- "nombre_experiences_precedentes": 2,
79
- "nombre_heures_travailless": 40,
80
- "annee_experience_totale": 5,
81
- "annees_dans_l_entreprise": 2,
82
- "annees_dans_le_poste_actuel": 1,
83
- "nombre_participation_pee": 1,
84
- "nb_formations_suivies": 3,
85
- "nombre_employee_sous_responsabilite": 0,
86
- "code_sondage": 7,
87
- "distance_domicile_travail": 12,
88
- "niveau_education": 3,
89
- "domaine_etude": "Marketing",
90
- "ayant_enfants": "Non",
91
- "frequence_deplacement": "Rarement",
92
- "annees_depuis_la_derniere_promotion": 0,
93
- "annes_sous_responsable_actuel": 1,
94
- "satisfaction_employee_environnement": 3,
95
- "note_evaluation_precedente": 4,
96
- "niveau_hierarchique_poste": 2,
97
- "satisfaction_employee_nature_travail": 3,
98
- "satisfaction_employee_equipe": 4,
99
- "satisfaction_employee_equilibre_pro_perso": 3,
100
- "eval_number": "E2",
101
- "note_evaluation_actuelle": 4,
102
- "heure_supplementaires": "Non",
103
- "augementation_salaire_precedente": 11
104
- }]
105
- }
106
-
107
-
108
- resp = client.post("/predict", json=payload)
109
-
110
- print("STATUS:", resp.status_code)
111
- print("BODY:", resp.text)
112
-
113
- app.dependency_overrides.clear()
114
- session.close()
115
-
116
- assert resp.status_code == 200
117
- data = resp.json()
118
- assert data["model_name"] == "best_model"
119
- assert isinstance(data["results"], list)
120
- assert len(data["results"]) == 1
121
-
122
- result = data["results"][0]
123
- assert result["label"] == "reste_dans_l_entreprise"
124
- assert isinstance(result["proba"], float)
125
- assert 0 <= result["proba"] <= 1
126
-
127
-
128
- def test_not_found_model(tmp_path):
129
- db_path = tmp_path / "testing.db"
130
- engine = create_engine(
131
- f"sqlite:///{db_path}",
132
- connect_args={"check_same_thread": False},
133
- future=True,
134
- )
135
- SQLSession = sessionmaker(bind=engine, autoflush=False, autocommit=False, future=True)
136
-
137
- MLModel.metadata.create_all(engine)
138
- MLInput.metadata.create_all(engine)
139
- MLOutput.metadata.create_all(engine)
140
-
141
- session = SQLSession()
142
-
143
- def get_db_override():
144
- return session
145
-
146
-
147
- app.dependency_overrides[get_db] = get_db_override
148
-
149
- client = TestClient(app, raise_server_exceptions=False)
150
-
151
- created = datetime(2025, 9, 15, 10, 11, 3, 950802, tzinfo=timezone.utc)
152
- session.add_all(
153
- [
154
- MLModel(
155
- id=uuid.UUID("5b1c7b3a-0000-4000-8000-000000000001"),
156
- name="baseline",
157
- description="Baseline model",
158
- created_at=created,
159
- is_active=True,
160
- ),
161
- ]
162
- )
163
- session.commit()
164
-
165
-
166
- payload = {
167
- "model_name": "best_model",
168
- "inputs": [{
169
- "id_employee": 123,
170
- "age": 35,
171
- "genre": "Homme",
172
- "revenu_mensuel": 4200,
173
- "statut_marital": "Célibataire",
174
- "departement": "Ventes",
175
- "poste": "Commercial",
176
- "nombre_experiences_precedentes": 2,
177
- "nombre_heures_travailless": 40,
178
- "annee_experience_totale": 5,
179
- "annees_dans_l_entreprise": 2,
180
- "annees_dans_le_poste_actuel": 1,
181
- "nombre_participation_pee": 1,
182
- "nb_formations_suivies": 3,
183
- "nombre_employee_sous_responsabilite": 0,
184
- "code_sondage": 7,
185
- "distance_domicile_travail": 12,
186
- "niveau_education": 3,
187
- "domaine_etude": "Marketing",
188
- "ayant_enfants": "Non",
189
- "frequence_deplacement": "Rarement",
190
- "annees_depuis_la_derniere_promotion": 0,
191
- "annes_sous_responsable_actuel": 1,
192
- "satisfaction_employee_environnement": 3,
193
- "note_evaluation_precedente": 4,
194
- "niveau_hierarchique_poste": 2,
195
- "satisfaction_employee_nature_travail": 3,
196
- "satisfaction_employee_equipe": 4,
197
- "satisfaction_employee_equilibre_pro_perso": 3,
198
- "eval_number": "E2",
199
- "note_evaluation_actuelle": 4,
200
- "heure_supplementaires": "Non",
201
- "augementation_salaire_precedente": 11
202
- }]
203
- }
204
-
205
-
206
- resp = client.post("/predict", json=payload)
207
-
208
-
209
- app.dependency_overrides.clear()
210
- session.close()
211
-
212
- assert resp.status_code == 404
213
- data = resp.json()
214
- assert data["detail"] == "Modèle introuvable ou inactif"
215
-
216
-
217
- def test_inactif_model(tmp_path):
218
- db_path = tmp_path / "testing.db"
219
- engine = create_engine(
220
- f"sqlite:///{db_path}",
221
- connect_args={"check_same_thread": False},
222
- future=True,
223
- )
224
- SQLSession = sessionmaker(bind=engine, autoflush=False, autocommit=False, future=True)
225
-
226
- MLModel.metadata.create_all(engine)
227
- MLInput.metadata.create_all(engine)
228
- MLOutput.metadata.create_all(engine)
229
-
230
- session = SQLSession()
231
-
232
- def get_db_override():
233
- return session
234
-
235
-
236
- app.dependency_overrides[get_db] = get_db_override
237
-
238
- client = TestClient(app, raise_server_exceptions=False)
239
-
240
- created = datetime(2025, 9, 15, 10, 11, 3, 950802, tzinfo=timezone.utc)
241
- session.add_all(
242
- [
243
- MLModel(
244
- id=uuid.UUID("5b1c7b3a-0000-4000-8000-000000000001"),
245
- name="baseline",
246
- description="Baseline model",
247
- created_at=created,
248
- is_active=False,
249
- ),
250
- ]
251
- )
252
- session.commit()
253
-
254
-
255
- payload = {
256
- "model_name": "baseline",
257
- "inputs": [{
258
- "id_employee": 123,
259
- "age": 35,
260
- "genre": "Homme",
261
- "revenu_mensuel": 4200,
262
- "statut_marital": "Célibataire",
263
- "departement": "Ventes",
264
- "poste": "Commercial",
265
- "nombre_experiences_precedentes": 2,
266
- "nombre_heures_travailless": 40,
267
- "annee_experience_totale": 5,
268
- "annees_dans_l_entreprise": 2,
269
- "annees_dans_le_poste_actuel": 1,
270
- "nombre_participation_pee": 1,
271
- "nb_formations_suivies": 3,
272
- "nombre_employee_sous_responsabilite": 0,
273
- "code_sondage": 7,
274
- "distance_domicile_travail": 12,
275
- "niveau_education": 3,
276
- "domaine_etude": "Marketing",
277
- "ayant_enfants": "Non",
278
- "frequence_deplacement": "Rarement",
279
- "annees_depuis_la_derniere_promotion": 0,
280
- "annes_sous_responsable_actuel": 1,
281
- "satisfaction_employee_environnement": 3,
282
- "note_evaluation_precedente": 4,
283
- "niveau_hierarchique_poste": 2,
284
- "satisfaction_employee_nature_travail": 3,
285
- "satisfaction_employee_equipe": 4,
286
- "satisfaction_employee_equilibre_pro_perso": 3,
287
- "eval_number": "E2",
288
- "note_evaluation_actuelle": 4,
289
- "heure_supplementaires": "Non",
290
- "augementation_salaire_precedente": 11
291
- }]
292
- }
293
-
294
-
295
- resp = client.post("/predict", json=payload)
296
-
297
- print("STATUS:", resp.status_code)
298
- print("BODY:", resp.text)
299
-
300
- app.dependency_overrides.clear()
301
- session.close()
302
-
303
- assert resp.status_code == 404
304
- data = resp.json()
305
- assert data["detail"] == "Modèle introuvable ou inactif"
306
-
307
-
308
- def test_list_models_returns_500_when_db_fails():
309
- class BrokenSession:
310
- def query(self, *a, **kw):
311
- raise RuntimeError("DB is down")
312
-
313
- def get_db_override():
314
- yield BrokenSession()
315
-
316
- app.dependency_overrides[get_db] = get_db_override
317
- client = TestClient(app, raise_server_exceptions=False)
318
-
319
- payload = {
320
- "model_name": "baseline",
321
- "inputs": [{
322
- "id_employee": 123,
323
- "age": 35,
324
- "genre": "Homme",
325
- "revenu_mensuel": 4200,
326
- "statut_marital": "Célibataire",
327
- "departement": "Ventes",
328
- "poste": "Commercial",
329
- "nombre_experiences_precedentes": 2,
330
- "nombre_heures_travailless": 40,
331
- "annee_experience_totale": 5,
332
- "annees_dans_l_entreprise": 2,
333
- "annees_dans_le_poste_actuel": 1,
334
- "nombre_participation_pee": 1,
335
- "nb_formations_suivies": 3,
336
- "nombre_employee_sous_responsabilite": 0,
337
- "code_sondage": 7,
338
- "distance_domicile_travail": 12,
339
- "niveau_education": 3,
340
- "domaine_etude": "Marketing",
341
- "ayant_enfants": "Non",
342
- "frequence_deplacement": "Rarement",
343
- "annees_depuis_la_derniere_promotion": 0,
344
- "annes_sous_responsable_actuel": 1,
345
- "satisfaction_employee_environnement": 3,
346
- "note_evaluation_precedente": 4,
347
- "niveau_hierarchique_poste": 2,
348
- "satisfaction_employee_nature_travail": 3,
349
- "satisfaction_employee_equipe": 4,
350
- "satisfaction_employee_equilibre_pro_perso": 3,
351
- "eval_number": "E2",
352
- "note_evaluation_actuelle": 4,
353
- "heure_supplementaires": "Non",
354
- "augementation_salaire_precedente": 11
355
- }]
356
- }
357
-
358
-
359
- resp = client.post("/predict", json=payload)
360
-
361
- app.dependency_overrides.clear()
362
-
363
- assert resp.status_code == 500
364
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
tests/unit/test_features.py DELETED
@@ -1,17 +0,0 @@
1
- import pandas as pd
2
- import pytest
3
- from features import compute_features
4
-
5
- def test_compute_features_returns_matrix():
6
- df = pd.DataFrame([{"age": 35, "genre": "Homme", "revenu_mensuel": 4200,
7
- "satisfaction_employee_environnement": 3,
8
- "satisfaction_employee_nature_travail": 3,
9
- "satisfaction_employee_equipe": 3,
10
- "satisfaction_employee_equilibre_pro_perso": 3, "note_evaluation_actuelle": 2, 'note_evaluation_precedente' : 3, "annes_sous_responsable_actuel" : 2, "annees_dans_le_poste_actuel" : 4, "niveau_hierarchique_poste": 2, "distance_domicile_travail" : 5}])
11
- X = compute_features(df)
12
- assert hasattr(X, "shape")
13
- assert X.shape[0] == 1
14
-
15
- def test_compute_features_raises_on_empty():
16
- with pytest.raises(Exception):
17
- compute_features(pd.DataFrame())