【Streamlit】テスト方法 – 単体テストやUIテストの基本

Streamlit
この記事は約7分で読めます。

こんにちは、JS2IIUです。
Streamlitのアプリが確実に意図通り動作するかを確認するためにテストを行う必要があります。テスト方法についてみていきます。今回もよろしくお願いします。

1. はじめに

StreamlitはPythonで簡単にWebアプリを作れる便利なフレームワークです。しかし、アプリの規模が大きくなると、動作が正しいかを確認するためのテストが重要になります。本記事では、初心者の方でも理解できるように、Streamlitアプリに対するテスト方法(単体テストとUIテスト)を、具体的なコード例とともにステップバイステップで解説します。

2. Streamlitアプリにおけるテストの考え方

StreamlitアプリはPythonで書かれているため、通常のPythonコードと同じようにテストができます。特に重要なのは、アプリのロジック部分(計算やデータ処理など)とUI部分を分けることです。これにより、ロジック部分は単体テスト、UI部分はUIテストで確認できるようになります。

  • 単体テスト:関数単位で個別に検証でき、処理の正確性を保証します。
  • UIテスト:ユーザー操作に近い形でアプリ全体を検証し、見た目や操作感を保証します。

3. 単体テスト(Unit Test)の基本と実践

3.1 単体テストとは?

単体テストは、小さな処理単位(主に関数やメソッド)が仕様通りに動作するかを確認するためのテストです。外部の状態(データベース、ファイル、UI)に依存せず、関数単体の入出力に注目することで、バグの原因を特定しやすくなります。

単体テストは、以下のようなメリットがあります:

  • バグの早期発見
  • リファクタリングの安全性確保
  • ドキュメント代わりになる(関数の使い方が明示される)

3.2 テスト対象の関数(例)

まず、テスト対象となるシンプルな関数を用意します。

Python
# utils.py

def calculate_total(price, quantity):
    return price * quantity

この関数は、価格と数量を掛け合わせて合計金額を返すだけのシンプルな処理です。

3.3 単体テストの書き方

pytestというPythonで広く使われているテストフレームワークを使ってテストコードを書きます。assert文を使って関数の出力が期待通りかどうかを検証します。

Python
# test_utils.py

from utils import calculate_total

def test_calculate_total():
    assert calculate_total(100, 2) == 200
    assert calculate_total(0, 5) == 0
    assert calculate_total(50, 0) == 0
    assert calculate_total(3.5, 2) == 7.0

3.4 pytestの実行方法

以下のコマンドでpytestをインストールします:

Bash
pip install pytest

テストを実行するには、次のコマンドを使用します:

Bash
pytest test_utils.py

出力例:

Plaintext
================== test session starts ==================
collected 1 item

test_utils.py .                                         [100%]

=================== 1 passed in 0.01s ===================

すべてのテストがパスしていれば、その関数は仕様通りに動いていると判断できます。

4. UIテスト(E2Eテスト)の基本と実践

4.1 UIテストとは?

UI(ユーザーインターフェース)テスト、特にエンドツーエンド(End-to-End, E2E)テストとは、ユーザーが実際にアプリを操作したときと同じ動作を自動で行い、表示内容やレスポンスの正しさを確認するテストです。

UIテストの目的:

  • ユーザー操作の流れが正しく動作するか検証
  • 表示内容が正しくレンダリングされているか確認
  • 回帰テストとして、変更が既存機能を壊していないか確認

4.2 テスト対象のStreamlitアプリを準備

以下のようなアプリをUIテストの対象とします:

Python
# app.py

import streamlit as st
from utils import calculate_total

st.title("合計金額計算アプリ")

price = st.number_input("価格", min_value=0)
quantity = st.number_input("数量", min_value=0)

if st.button("計算"):
    total = calculate_total(price, quantity)
    st.write("合計金額:", total)

4.3 Playwrightを使ったUIテスト

PlaywrightはモダンなE2Eテストツールで、複数ブラウザに対応しており、非同期操作やUIの状態を検知する機能が豊富です。

4.3.1 Playwrightのインストールとセットアップ

Bash
pip install playwright
playwright install

4.3.2 テストコードの作成

Python
# test_ui.py

from playwright.sync_api import sync_playwright

def test_calculate_app():
    with sync_playwright() as p:
        browser = p.chromium.launch()
        page = browser.new_page()
        page.goto("http://localhost:8501")

        # UIが表示されるまで少し待つ
        page.wait_for_timeout(3000)

        # 値を入力
        page.get_by_label("価格").fill("100")
        page.get_by_label("数量").fill("2")

        # ボタンをクリック
        page.get_by_text("計算").click()

        # 結果の確認
        page.wait_for_timeout(1000)
        assert "合計金額: 200" in page.content()

        browser.close()

4.3.3 テスト実行手順

  1. 別ターミナルでアプリを起動しておきます:
Bash
streamlit run app.py
  1. テストを実行:
Bash
python test_ui.py

テストが成功すれば、アプリのUIと処理が想定通りに動作していることが確認できます。

5. テストしやすいStreamlitアプリの書き方

Streamlitアプリをテストしやすくするためには、以下のような設計が重要です:

  • 関数を外部ファイルに分離(ビジネスロジックをUIから切り離す)
  • ステートやグローバル変数への依存を減らす
  • コンポーネントの状態変化が明示されている

例:改善前と改善後

改善前(テストしにくい)

Python
st.write("合計:", 100 * 2)

改善後(テストしやすい)

Python
def calculate_total(price, quantity):
    return price * quantity

total = calculate_total(100, 2)
st.write("合計:", total)

6. よくあるエラーと対処法

エラー内容原因対処法
ConnectionErrorStreamlitアプリが起動していないstreamlit runコマンドでアプリを起動
要素が見つからないラベル名がUIと一致していないget_by_labelget_by_text を再確認
UI読み込みの遅延DOMの反映が間に合っていないwait_for_timeoutwait_for_selector を利用

7. まとめ

  • 単体テストはロジックの正確さを保証し、保守性を向上させる
  • UIテストはアプリの完成度とユーザー体験を保証する
  • Playwrightなどのツールを使えば、Streamlitアプリも自動テスト可能
  • テスト可能なコード設計を意識することで、品質と開発効率が向上する

8. 参考リンク

最後まで読んでいただきありがとうございます。

コメント

タイトルとURLをコピーしました