Streamlitでもテスト書きたい

こんにちは

こんにちは。estieでデータサイエンスをしている齊藤です。

本日は8/10、そう、ヤドンの日ですね。今年もブログを書けることをうれしく思います。(2022, 2023

最近一周年を迎えた、ポケモンスリープにはまっています。ヤドンのしっぽは非常に高エナジーですが(ヤドンは遅いため)大量に集めるのが難しいというゲームバランス、最高です。

グッズも続々と発売されていて、最近ではジェラートピケのヤドンなりきりセットの販売が界隈で話題となりました。羽田空港のイベントも大盛況でしたね。

羽田空港のイベントを楽しむ筆者

ヤドンというポケモンはすぐにドわすれしてしまいます。私もすぐにドわすれしてしまうので、思いついたアイデアはすぐに形にする必要があります。

Streamlitについて

Streamlitは、簡単に良いかんじのWebアプリを今すぐ作りて〜という欲求を持つ方に大人気のフレームワークです。

もちろん僕もその一人で、アイデアが浮かんでから忘れないうちにすぐ動く物ができるので、日々Streamlitでアプリ作りを楽しんでいます。

StreamlitはSnowflake社に買収され、新機能の開発もさらに活発に進められています(もともと活発でしたが)。

最近はSnowflakeの画面上で簡単にStreamlitアプリが作れたりしますね!

簡単テストのすすめ

Streamlitを使う主なモチベーションは「めっちゃ簡単にWebアプリ作りたい!」という方が多いと思います。なのでテストまで作り込まなくてもいいんじゃない?と思うこともあるでしょう。特にプロトタイプとしてアプリを作った場合、その傾向は強いかもしれません。

しかし、プロトタイプが好評でアプリの寿命が延びることも往々にしてあります。また、社内アプリとしてしばらく使いたい時もあるでしょう。あるいは、テストを書かないデータサイエンティストに怒る記事を最近読んだかもしれません。

そんな時にテストを書きたくなるものですが、最初のモチベーションが「簡単に作りたい」だったため、SeleniumやPlaywrightを導入するのは(Streamlitを覚えたばかりなのに!)少し気が重くなるかもしれません。

実は、StreamlitにはデフォルトでApptestというテストモジュールが用意されています。まずはここから始めてみましょう。

簡単に「とりあえず起動して画面を描画した際にエラーが起きないか」をテストすることができます。

# app_test.py
from streamlit.testing.v1 import AppTest

def test_run_app():
    at = AppTest.from_file("app.py").run()
    assert not at.exception

app.py のパスを直接書くのが微妙だなと思ったら、テストしたい関数をインポートしてテストすることもできます。(個人的にはこっちの方が好み)

# app_test.py
from streamlit.testing.v1 import AppTest
from app import main

def test_run_app():
    at = AppTest.from_function(main).run()
    assert not at.exception

このapp_test.pyをここにおけばOKです。

.
├── app.py
└── tests
   └── app_test.py

pytestなりunittestなりお好みのフレームワークで実行することが出来ます。

このテストはアプリの内容に依存しないのでアプリを作るときにセットで入れておくと良いです。

前述のようにStreamlitは開発が激しく、どんどん関数がdeprecatedしていくので、こういうテストがあると安心してバージョンをあげていくことができます!

ただ testing.v1 とあるように新しいテストの方法が出てくるのかもしれません。

通常のテスト

もちろん、もう少しメインシナリオに沿ったテストを書くこともできます。

import streamlit as st

option = st.selectbox(
    label="どのポケモンが好きですか?",
    options=("イーブイ", "カビゴン", "ヤドン"),
    key="pokemon",
)
if option == 'ヤドン':
    st.info('ヤドンはかわいいですね!', icon='😍')
else:
    st.error('わかります、でももう一度考えてみてください。', icon='🤔')

上記のアプリに対して、例えば以下のようなシナリオを書くことができます。

def test_choose_pokemon():
    at = AppTest.from_function(main).run()
    
    # ヤドンを選ぶとエラーにならない
    at.selectbox(key="pokemon").set_value("ヤドン").run()
    assert not at.error
    assert at.info[0].icon == "😍"
    
    # ヤドン以外だとエラーメッセージを表示する
    at.selectbox("pokemon").set_value("イーブイ").run()
    assert at.error[0].icon == "🤔"

selectboxの選択肢によって表示が変わりますが、意図通りになっているかをチェックすることができます!

テストの際には、streamlitの要素をキーで選んで操作することができます。

これでアプリを量産することができます!

AppTestの制限

いくつかの要素については、2024/08/10 現在 Apptestで操作することができません。 ref: App testing cheat sheet - Streamlit Docs

例: st.file_uploader, st.imageなど

Apptest.file_uploaderを一緒に開発していきましょう。

hrmos.co

© 2019- estie, inc.