pytest匷åã·ãªãŒãº
ã¯ããã«
ç§ã¯çŸåšãæ¬æ¥ã§ãã©ãã¯ãã©ã€ããŒãšããŠåããªãããPythonãFlaskã䜿ã£ãWebã¢ããªã±ãŒã·ã§ã³éçºãç¬åŠããŠããŸãã
ãã®èšäºå·çæç¹ã§ã环èšåŠç¿æéã¯167æéã§ãã
以åãå人éçºäžã®ã¢ããªã«ãã£ãpytestãèŠçŽãããšããããã¹ãã¯3ä»¶ãããªãã
ããã¹ãã¯ããããã©ãæ¬åœã«å€§äºãªãšãããå®ããŠããã®ã ãããïŒã
ãšããçåãåºãŠããŸããã
ããã§ãpytestãåãªãåäœç¢ºèªã§ã¯ãªãã
äžåºŠèŠã€ããåé¡ããåãç¶æ ã«æ»ããªãããã®ãäºæ 鲿¢å°åž³ã
ãšããŠè²ãŠãããšã«ããŸããã
第1段éã§ã¯ã3ä»¶ã ã£ããã¹ãã9ä»¶ãŸã§å¢ããã
- AIãžæž¡ãããã³ãã
- XSS察ç
- Gemini APIãã¢ãã¯ãã飿ºç¢ºèª
- GitHub Actionsã§ãã¹ãŠã®pytestãå®è¡
ãšãã£ãéšåã確èªã§ããããã«ããŸããã
ä»åã¯ãã®ç¶ããšããŠã第2段éãé²ããŸããã
æçµçã«pytestå šäœã¯ã
51 passed
ãŸã§å¢ããŸããã
ãã ãä»åéèŠããã®ã¯ããã¹ãä»¶æ°ãå¢ããããšãã§ã¯ãããŸããã
売äžãååããŒã¿ãæ±ããšãã«ãä»åæ³å®ããäžæ£å ¥åãDBä¿å倱æã§ãDBãããããªç¶æ ã«ããªãããš
ãäžå¿ã«ç¢ºèªããŸããã
ä»åã®ç¬¬2段éã§ç¢ºèªããããš
倧ããåãããšã次ã®å 容ã§ãã
- 売äžå ¥åã®äžæ£ããŒã¿ãæåŠãã
- ééã£ãååãžã®å£²äžç»é²ãé²ã
- åãååã»åãæ¥ã®å£²äžãéè€ããªãããDBåŽã§ãé²ã
- DBä¿åã«å€±æããã倿Žãå ã«æ»ã
- ååç»é²ã»æŽæ°æã®äžæ£å ¥åãæåŠãã
- 販売çµäºããŠãéå»ã®å£²äžå±¥æŽãæ®ã
- ããã·ã¥ããŒãã®éèšçµæãDBãšäžèŽããããšã確èªãã
æåã¯ã
ã売äžå ¥åã®ãã¹ããå°ãå¢ãããã
ãããã®ã€ããã§ããã
ãããäžã€ãã€ç¢ºèªããŠãããšã
å ¥å â DBä¿å â å±¥æŽä¿æ â éèšè¡šç€º
ãŸã§ã€ãªãã£ãŠãããããæ³å以äžã«åºãç¯å²ã«ãªããŸããã
1. 売äžå ¥åã¯ã1ä»¶ã§ããããããã°å šéšæ¢ããã
ãŸã確èªããã®ãã売äžå ¥åç»é¢ããéä¿¡ãããããŒã¿ã§ãã
Webãã©ãŒã ããéãããããŒã¿ãFlaskåŽã§åãåãåŠçãããã®èšäºã§ã¯ã売äžPOSTããšåŒã³ãŸãã
ããšãã°ã
ååA 5å
ååB 3å
ãšå ¥åããŠéä¿¡ãããšã
Flaskããã®å 容ãåãåããDBãžä¿åããŸãã
ããã§åé¡ã«ãªã£ãã®ãã
äžéšã ãäžæ£ãªããŒã¿ãæ··ãã£ãå Žå
ã§ããã
確èªããã±ãŒã¹ã«ã¯ã
- æ¥ä»ããããã
- æ°éã空
- æ°éã«æ°å以å€ã®æåãå ¥ã£ãŠãã
- è² ã®æ°é
- å°æ°
- ååIDãšæ°éã®ä»¶æ°ãåããªã
- ååIDã空
- ååIDã«æ°å以å€ã®æåãå ¥ã£ãŠãã
- åãååIDãéè€
- ååã»æ°éã®é åèªäœã空
ãªã©ããããŸãã
ä¿®æ£åã«ã¯ãããšãã°å°æ°ãæŽæ°ãžå€æããŠããŸã£ãããäžæ£ãªè¡ã ããé£ã°ããŠæ£åžžãªè¡ãä¿åããçµè·¯ããããŸããã
ããã§æ¹éãã
1ä»¶ã§ãäžæ£ãªããŒã¿ãããã°ããã®ãªã¯ãšã¹ãå šäœãæåŠãã
ã«å€æŽããŸããã
pytestã§ã¯HTTP 400ã«ãªãããšã ãã§ãªãã
POSTååŸã§DailySalesã®äžèº«ãå€ãã£ãŠããªãããš
ãŸã§ç¢ºèªããŠããŸãã
ã€ãŸãã
ååAïŒ5 â 9ãžå€æŽäºå®
ååBïŒäžæ£ããŒã¿
â å
šäœãæåŠ
ååAïŒ5ã®ãŸãŸ
ååBïŒä¿åãããªã
ãšããç¶æ ã確èªããŠããŸãã
2. ãååšããååãªãäœã§ãOKãã§ã¯ãªãã£ã
次ã«ç¢ºèªããã®ãã売äžãç»é²ãã察象ã®ååã§ãã
ååIDãæ°åãšããŠæ£ãããŠãã
- DBã«ååšããªãåå
- å£²äžæ¥ãšã¯å¥ã®å¹Žæã®åå
- 販売çµäºããåå
ã«ã¯å£²äžãç»é²ãããããããŸããã
ããã§pytestã远å ãã
äžæåå
奿ã®åå
販売çµäºåå
ããã¹ãŠHTTP 400ã§æåŠããããã«ããŸããã
ããã§ãã
æ£åžžãªååãäžç·ã«éã£ãŠããŠãDailySalesã倿Žããªã
ããšã確èªããŠããŸãã
販売çµäºããååã«éå»ã®å£²äžããã§ã«ååšããå Žåãã
ãã®å±¥æŽèªäœã¯å€æŽãããŸããã
3. DBèªèº«ã«ããåãæ¥ã®å£²äžã¯1ä»¶ã ãããšèŠããŠããã
ã¢ããªåŽã§ã¯ä»¥åããã
åãååã»åãæ¥ä»ã®å£²äžãååšããã°ãæ°ããè¡ã远å ããæ°éãæŽæ°ãã
ãšããåŠçããããŸããã
ããããDBãã®ãã®ã«ã¯ã
åãåå
+
åãæ¥ä»
ãéè€çŠæ¢ã«ããã«ãŒã«ããããŸããã§ããã
ããã§ã
(product_id, date)
ã®çµã¿åããã«äžæå¶çŽã远å ããŸããã
äžæå¶çŽãšã¯ãç°¡åã«èšãã°ã
ããã®çµã¿åããã¯DBå ã«1ã€ããååšã§ããŸããã
ãšããã«ãŒã«ã§ãã
ã¢ããªåŽã§éè€ãé¿ããã ãã§ãªããDBåŽã§ãæåŠããäºéãã§ãã¯ã«ããŸããã
pytestã§ã¯Flaskã®ç»é¢ãéããããã¹ãDBãžçŽæ¥åãååã»åãæ¥ä»ã®å£²äžã2ä»¶ä¿åããããšããŠã
IntegrityError
ã«ãªãããšã確èªããŠããŸãã
åäžååã»åäžæ¥ã®éè€ã«ã€ããŠã¯ã
ã¢ããªåŽã®åŠçãããæããŠãDBåŽã®äžæå¶çŽã§æ¢ããããç¶æ ã«ããŸããã
ä»åã¯ããã®ç¶æ ãäœãããšãç®çã§ããã
4. ãã€ã°ã¬ãŒã·ã§ã³ãéé¢ããPostgreSQLã§ç¢ºèª
DBã®èšèšã倿ŽãããããAlembicã®ãã€ã°ã¬ãŒã·ã§ã³ã远å ããŸããã
ãã€ã°ã¬ãŒã·ã§ã³ã¯ã
DBã®èšèšå€æŽãå±¥æŽãšããŠæ®ããé çªã«é©çšããããã®ä»çµã¿
ãšããŠçè§£ããŠããŸãã
ä»å远å ããå 容ã¯ã
DailySales(product_id, date)
ãžäžæå¶çŽã远å ãã倿Žã§ãã
ãã ããæ®æ®µäœ¿ã£ãŠããPostgreSQLãžãããªãé©çšããã®ã¯é¿ããŸããã
éåžžç°å¢ãšã¯å¥ã®Dockerç°å¢ãäœãã
- 空DBããææ°ç¶æ ãŸã§upgrade
- æ¢åDBçžåœã®ç¶æ ããupgrade
- downgrade
- åupgrade
- æ¢åããŒã¿ã®ä»¶æ°ã»å 容ãå€ãã£ãŠããªãããš
ã確èªããŸããã
ããã«éè€INSERTãè¡ããPostgreSQLèªèº«ãäžæå¶çŽéåãšããŠæåŠããããšã確èªããŸããã
æ€èšŒåŸã¯ãéé¢ç°å¢ã®ã³ã³ããã»volumeãªã©ãåé€ããŠããŸãã
ããã§ãã
éåžžç°å¢ã§è©ŠããŠåé¡ãèµ·ãããæ»ã
ã®ã§ã¯ãªãã
倱æããŠãéåžžç°å¢ãžåœ±é¿ããªãå Žæã§å ã«è©Šã
ããšãæèããŸããã
5. ä¿å倱ææã¯rollbackãã
次ã«ç¢ºèªããã®ãã
å ¥åã¯æ£åžžã ã£ãããã©ãæåŸã®DBä¿åã§å€±æããå Žå
ã§ãã
DBãžã®ä¿åã§ã¯ãæåŸã«commit()ãå®è¡ããŸãã
ç°¡åã«èšããšã
ãããŸã§ã®å€æŽãæ£åŒã«ä¿åãã
åŠçã§ãã
ããããããã§ãšã©ãŒãèµ·ããå¯èœæ§ããããŸãã
売äžPOSTã®å Žå
äŸãã°ã
ååAïŒ5å â 9åãžæŽæ°äºå®
ååBïŒ7åãæ°èŠè¿œå äºå®
ãšãã倿Žãé²ããããšãæåŸã®commit()ã§ãšã©ãŒã«ãªã£ãå Žåã§ãã
ãã®ãšããä¿åã«å€±æãã倿Žãæç€ºçã«åãæ¶ããDBã»ãã·ã§ã³ãæ»ãåŠçãå¿ èŠã«ãªããŸãã
ããã§ã
db.session.rollback()
ã远å ããŸããã
pytestã§ã¯commit()ãæå³çã«å€±æããã
ååAã®DailySalesïŒquantity=5ã®ãŸãŸ
ååBã®DailySalesïŒæ°èŠè¿œå ãããªã
DailySalesä»¶æ°ïŒå€åãªã
ãšãªãããšã確èªããŸããã
ååPOSTã®å Žå
ååç»é²ã»æŽæ°åŽã§ãåãããã«commit()ãæå³çã«å€±æãããŠããŸãã
ãã¡ãã§ã¯ã
- æ¢åååã®ååã»äŸ¡æ Œã»è²©å£²ç¶æ
- æ°èŠååã®è¿œå
- DailySales
ãPOSTåã®ç¶æ ããå€ãã£ãŠããªãããšã確èªããŸããã
ã€ãŸãã
å ¥åæ€èšŒã ãã§ãªããæåŸã®ä¿ååŠçãã®ãã®ã倱æããå Žåããéäžã®å€æŽãæ®ããªã
ããšãååž°ãã¹ãã«ããŸããã
6. ååç»é²åŽã17çš®é¡ã®äžæ£å ¥åã確èª
売äžå ¥åã ãã§ã¯ãªããååãã¹ã¿ãç»é²ã»æŽæ°ããç»é¢ã確èªããŸããã
ä¿®æ£åã«ã¯ã
- å
¥åé
ç®ã®ä»¶æ°ãåããªããŠã
zip()ã§äœã£ãå€ãç¡èŠããã - æ°å以å€ã®ååIDãéããã
- ååšããªãååIDãéããã
- 奿ã®ååIDãéããã
- åãååIDãè€æ°åéã
- äžæ£ãªäŸ¡æ Œãéããã
- yearã»monthã空ãŸãã¯æ°åã§ã¯ãªã
-
month=0ãmonth=13ãéããã
ãšãã£ãã±ãŒã¹ãååã«æåŠã§ããŠããªãçµè·¯ããããŸããã
ããã§17çš®é¡ã®äžæ£å ¥åã±ãŒã¹ã远å ããŸããã
ä¿®æ£åã¯ã
17 failed
ä¿®æ£åŸã¯ã
17 passed
ãšãªããŸããã
ããã§ãéèŠãªã®ã¯ã
HTTP 400ãè¿ãã ãã§ã¯ãªããProductãšDailySalesãPOSTååŸã§å€ãã£ãŠããªãããš
ã§ãã
ååç»é²ã§ãã
ãã¹ãŠæ€èšŒ
â
å
šéšæ£åžž
â
åããŠDBã倿Ž
ãšããé çªã«ããŸããã
æ£åžžç³»ã«ã€ããŠãã
- æ¢åååã®æŽæ°
- æ°èŠååã®è¿œå
- äŸ¡æ Œ0åã®åå
- 売äžå±¥æŽã倿Žããªãããš
ã確èªããŠããŸãã
7. 販売çµäºããŠãéå»ã®å£²äžã¯æ¶ããªã
ãã®ã¢ããªã§ã¯ãååã販売çµäºã«ããŠãDBããåé€ããŸããã
is_active=True
â
is_active=False
ãšãããè«çåé€ãã䜿ã£ãŠããŸãã
ããã«ã¯çç±ããããŸãã
ååãã®ãã®ãåé€ããŠããŸããšããã®ååã«çŽã¥ãéå»ã®å£²äžå±¥æŽãŸã§æ±ãã«ãããªãããã§ãã
ä»åpytestã§ã
- ååè¡ãã®ãã®ã¯æ®ã
- Product IDã¯å€ãããªã
-
is_active=Falseã«ãªã - éå»ã®DailySalesã¯æ®ã
ããšã確èªããŸããã
ããã«ã販売çµäºããååã®æ¢åProduct IDãåéä¿¡ããå Žåãã
æ°ããååãäœã
ã®ã§ã¯ãªãã
åãProduct ID
â
is_active=True
ãžæ»ãããšã確èªããŠããŸãã
ãã®éã
- Productä»¶æ°ãå¢ããªã
- éå»ã®DailySalesãå€ãããªã
- åãProduct IDã䜿ãç¶ãã
ããšã確èªããŸããã
ãã®2ã€ã®ãã¹ãã¯ã远å ããæç¹ããæåããŸããã
ã€ãŸãä»åã¯ã³ãŒããçŽããã®ã§ã¯ãªãã
ãã§ã«æ£ããåããŠãã仿§ããä»åŸå£ããªãããpytestã«èšé²ãã
圢ã§ãã
8. æåŸã¯ããã·ã¥ããŒãã®éèšãŸã§ç¢ºèª
第2段éã®æåŸã«ãããã·ã¥ããŒãAPIã確èªããŸããã
DBãžå£²äžããŒã¿ãå ¥ãã
ååA
3å + 7å = 10å
ååB
5å
ãšããç¶æ ãäœããŸãã
ãã®ããã§ã
/api/dashboard-data?year=2026&month=8
ãžã¢ã¯ã»ã¹ãã
ååAïŒ10
ååBïŒ5
ãšããçµæã«ãªãããšãpytestã§ç¢ºèªããŸããã
ããã«ã
ranked_sales
chart_labels
chart_values
ã®é çªãšæ°éãäžèŽããããšã確èªããŠããŸãã
販売çµäºããååã®éå»å£²äžãéèšå¯Ÿè±¡ãšããŠæ®ãã
ãã£ã«ã¿ãä»ããªããã°ã
å
šæé
ã®å£²äžãéèšãããããšããã¹ãããŸããã
ãã®ããã·ã¥ããŒãAPIã®4ä»¶ã¯ã远å ããæç¹ãããã¹ãŠæåããŸããã
ã€ãŸãããã§ãã
çŸåšãã§ã«æ£ããåããŠããéèšä»æ§ããå°æ¥å£ããªãããã«ãã¹ããžæ®ãã
圢ã§ãã
ãŸãããã®APIã®ãã¹ãã§ã¯Gemini ClientãåŒã³åºããªãããšãåæã«ããDBéèšéšåãå€éšAPIããåãé¢ããŠç¢ºèªããŠããŸãã
9ä»¶ãã51ä»¶ãž
第1段éçµäºæç¹ã§ã¯ã
9 passed
ã§ããã
第2段éçµäºæç¹ã§ã¯ã
51 passed
ã«ãªããŸããã
ãã ãã
51ä»¶ããããå®å š
ãšããæå³ã§ã¯ãããŸããã
pytestã¯ããã¹ããšããŠæžããå 容ãã確èªã§ããŸããã
ä»åãäœæ¥äžã«ã
- åãåååãæã€å¥Product IDãã©ã®ããã«éèšããã
- åååã®æåæ°å¶é
- yearã®èš±å®¹ç¯å²
- åæ°éååã®ã©ã³ãã³ã°é
- 売äž0ä»¶æã®API仿§
ãªã©ããŸã 仿§ã決ããŠããªãé ç®ãèŠã€ãã£ãŠããŸãã
ãããã«ã€ããŠã¯ã
仿§ã決ãŸã£ãŠããªããŸãŸCodexã«å€æãããŠä¿®æ£ç¯å²ãåºããããšã¯ããŸããã§ããã
ä»åã®äœæ¥ç¯å²ããå€ããæªå¯Ÿå¿äºé ãšããŠæ®ããŠããŸãã
ãã¹ãä»¶æ°ãã®ãã®ããã
ã©ããªäºæ ãé²ãããã®ãã¹ããªã®ã
ãææ¡ããŠããæ¹ã倧åã ãšæããŸããã
ä»åãã£ãŠã¿ãŠåãã£ãããš
ä»åã®ç¬¬2段éã§ã¯ãæåãã倧ããªãã¹ãèšç»ãå®ç§ã«äœã£ãŠããããã§ã¯ãããŸããã
äžã€ç¢ºèªãããšã
ãã§ã¯ããã®å Žåã¯ïŒã
ãšãã穎ãèŠã€ããããŸããã¹ãã远å ããã
ãã®ç¹°ãè¿ãã§ããã
çµæãšããŠã
å
¥åå€
â
åå確èª
â
DBä¿å
â
倱æærollback
â
å±¥æŽä¿æ
â
éèš
ãŸã§ç¢ºèªããããšã«ãªããŸããã
ãã©ãã¯ã®ä»äºã§èãããšã
ãäºæ ãèµ·ãããªãããæ³šæããã
ã ãã§ã¯ãªãã
- å±éºãªè·ç©ã¯ç©ãŸããªã
- ç©ã¿æ¹ããããããã°åºçºãããªã
- åé¡ãèµ·ãããéäžã§æ¢ãã
- éå»ã®èšé²ãæ®ã
- æåŸã«çµæã確èªãã
ãšããä»çµã¿ãäœãæèŠã«è¿ãæ°ãããŸãã
ãŸãšã
ä»åã®pytest匷å 第2段éã§ã¯ã
- 売äžPOSTã®å šä»¶äºåæ€èšŒ
- ååã®ååšã»å¹Žæã»è²©å£²ç¶æ 確èª
-
(product_id, date)ã®DBäžæå¶çŽ - Alembicãã€ã°ã¬ãŒã·ã§ã³
- éé¢PostgreSQLã§ã®upgrade / downgrade確èª
- 売äžPOSTã®rollback
- ååPOSTã®17çš®é¡ã®äžæ£å ¥åæ€èšŒ
- ååPOSTã®rollback
- è«çåé€ãšéå»å£²äžå±¥æŽã®ä¿æ
- dashboard APIã®DBéèš
ãŸã§ç¢ºèªããŸããã
pytestå šäœã¯ã
9 passed
â
51 passed
ãšãªããŸããã
ä»åæ¹ããŠæããã®ã¯ã
ãåããã¹ãããªãããæ°ãã€ããããããåãå±éºãªç¶æ ã«ãªã£ããèªåã§æ¢ãŸãä»çµã¿ãäœãæ¹ãåçºé²æ¢ã«ãªã
ãšããããšã§ãã
äžæ¹ã§ããŸã 仿§ã決ããŠããªãé ç®ããä»åæ±ã£ãŠããªãé åããããŸãã
æ¬¡ã®æ®µéã§ã¯ãèªèšŒã»èªå¯ã»CSRFãªã©ã
ã誰ããã®æäœãããŠããã®ãã
ãšããéšåã確èªããŠããäºå®ã§ãã
pytestããäºæ 鲿¢å°åž³ããšããŠè²ãŠãäœæ¥ã¯ãããå°ãç¶ãããã§ãã
pytest匷åã·ãªãŒãº
