0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

📝pytestを「事故防止台垳」ずしお育おる 第2段階売䞊・商品登録たわりを51件のテストたで匷化した蚘録

0
Last updated at Posted at 2026-08-10

ChatGPT Image 2026幎8月10日 21_45_50.png

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匷化シリヌズ


0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?