test-shiny-app
정보
이 스킬은 개발자가 Shiny 애플리케이션을 테스트할 수 있도록 지원합니다. shinytest2를 이용한 엔드투엔드 브라우저 테스트와 testServer()를 활용한 모듈 로직 단위 테스트를 제공합니다. 스냅샷 테스트, CI 통합, 외부 서비스 모킹 등을 처리할 수 있습니다. 기존 앱에 테스트를 추가할 때, 새 프로젝트의 테스트 전략을 설정할 때, 리팩토링 전 회귀 테스트를 작성할 때, 또는 CI/CD 파이프라인에 테스트를 통합할 때 활용하세요.
빠른 설치
Claude Code
추천npx skills add pjt222/agent-almanac -a claude-code/plugin add https://github.com/pjt222/agent-almanacgit clone https://github.com/pjt222/agent-almanac.git ~/.claude/skills/test-shiny-appClaude Code에서 이 명령을 복사하여 붙여넣어 스킬을 설치하세요
문서
name: test-shiny-app description: > エンドツーエンドのブラウザテストにshinytest2を、モジュールサーバーロジックの ユニットテストにtestServer()を使ってShinyアプリケーションをテストします。 スナップショットテスト、CIインテグレーション、外部サービスのモックを扱います。 既存のShinyアプリケーションにテストを追加するとき、新しいShinyプロジェクトの テスト戦略をセットアップするとき、Shinyコードをリファクタリングする前に リグレッションテストを書くとき、またはShinyアプリのテストをCI/CDパイプラインに 統合するときに使用します。 locale: ja source_locale: en source_commit: 6f65f316 translator: claude-opus-4-6 translation_date: 2026-03-16 license: MIT allowed-tools: Read Write Edit Bash Grep Glob metadata: author: Philipp Thoss version: "1.0" domain: shiny complexity: intermediate language: R tags: shiny, testing, shinytest2, testServer, snapshot, CI
Shinyアプリのテスト
shinytest2(エンドツーエンド)とtestServer()(ユニットテスト)を使ってShinyアプリケーションの包括的なテストをセットアップします。
使用タイミング
- 既存のShinyアプリケーションにテストを追加するとき
- 新しいShinyプロジェクトのテスト戦略をセットアップするとき
- Shinyコードをリファクタリングする前にリグレッションテストを書くとき
- ShinyアプリのテストをCI/CDパイプラインに統合するとき
入力
- 必須: Shinyアプリケーションへのパス
- 必須: テストのスコープ(ユニットテスト、エンドツーエンド、または両方)
- オプション: スナップショットテストを使用するか(デフォルト:e2eではあり)
- オプション: CIプラットフォーム(GitHub Actions、GitLab CI)
- オプション: 分離してテストするモジュール
手順
ステップ1: テスト依存関係のインストール
install.packages("shinytest2")
# golemアプリの場合、Suggests依存関係として追加
usethis::use_package("shinytest2", type = "Suggests")
# testthatインフラがない場合はセットアップ
usethis::use_testthat(edition = 3)
期待結果: shinytest2がインストールされ、testthatディレクトリ構造が整っています。
失敗時: shinytest2にはchromore(ヘッドレスChrome)が必要です。システムにChrome/Chromiumをインストールしてください。WSLの場合:sudo apt install -y chromium-browser。chromote::find_chrome()で確認してください。
ステップ2: モジュールのtestServer()ユニットテストの記述
tests/testthat/test-mod_dashboard.Rを作成します:
test_that("dashboard module filters data correctly", {
testServer(dataFilterServer, args = list(
data = reactive(iris),
columns = c("Species", "Sepal.Length")
), {
# 入力を設定
session$setInputs(column = "Species")
session$setInputs(value_select = "setosa")
session$setInputs(apply = 1)
# 出力を確認
result <- filtered()
expect_equal(nrow(result), 50)
expect_true(all(result$Species == "setosa"))
})
})
test_that("dashboard module handles empty data", {
testServer(dataFilterServer, args = list(
data = reactive(iris[0, ]),
columns = c("Species")
), {
# モジュールは空のデータでエラーを出してはいけない
expect_no_error(session$setInputs(column = "Species"))
})
})
主要なパターン:
testServer()はブラウザなしでモジュールサーバーロジックをテストするargsリストでリアクティブな引数を渡すsession$setInputs()でユーザーインタラクションをシミュレートする- リアクティブな戻り値には名前で直接アクセスする
- エッジケースをテストする:空のデータ、NULL入力、無効な値
期待結果: devtools::test()でモジュールテストが通過します。
失敗時: testServer()が「not a module server function」でエラーになる場合は、関数が内部でmoduleServer()を使用していることを確認してください。session$setInputs()がリアクティブをトリガーしない場合は、入力を設定した後にsession$flushReact()を追加してください。
ステップ3: shinytest2エンドツーエンドテストの記述
tests/testthat/test-app-e2e.Rを作成します:
test_that("app loads and displays initial state", {
# golemアプリの場合
app <- AppDriver$new(
app_dir = system.file(package = "myapp"),
name = "initial-load",
height = 800,
width = 1200
)
on.exit(app$stop(), add = TRUE)
# アプリが読み込まれるのを待つ
app$wait_for_idle(timeout = 10000)
# 主要な要素が存在するか確認
app$expect_values()
})
test_that("filter interaction updates the table", {
app <- AppDriver$new(
app_dir = system.file(package = "myapp"),
name = "filter-interaction"
)
on.exit(app$stop(), add = TRUE)
# アプリと対話する
app$set_inputs(`filter1-column` = "cyl")
app$wait_for_idle()
app$set_inputs(`filter1-apply` = "click")
app$wait_for_idle()
# 出力値のスナップショット
app$expect_values(output = "table")
})
主要なパターン:
AppDriver$new()がヘッドレスChromeでアプリを起動する- クリーンアップのために常に
on.exit(app$stop())を使用する - モジュールの入力IDは
"moduleId-inputId"形式を使用する app$expect_values()がスナップショットファイルを作成/比較するapp$wait_for_idle()がリアクティブな更新の完了を保証する
期待結果: エンドツーエンドテストがtests/testthat/_snaps/にスナップショットファイルを作成します。
失敗時: Chromeが見つからない場合は、CHROMOTE_CHROME環境変数をChromeバイナリのパスに設定してください。CIではスナップショットが失敗するがローカルでは通過する場合は、プラットフォーム依存のレンダリングの差異を確認してください。視覚的なスナップショットにはapp$expect_screenshot()ではなくapp$expect_values()を使用してください。
ステップ4: インタラクティブなテスト記録(オプション)
shinytest2::record_test("path/to/app")
これはブラウザで記録パネル付きのアプリを開きます。アプリと対話し、「Save test」をクリックしてテストコードを自動生成します。
期待結果: 記録されたインタラクションを含むテストファイルがtests/testthat/に生成されます。
失敗時: レコーダーが開かない場合は、まずshiny::runApp()でアプリが正常に起動することを確認してください。レコーダーには動作するアプリが必要です。
ステップ5: スナップショット管理のセットアップ
スナップショットベースのテストの場合、期待値を管理します:
# レビュー後に新しい/変更されたスナップショットを受け入れる
testthat::snapshot_accept("test-app-e2e")
# スナップショットの差異をレビュー
testthat::snapshot_review("test-app-e2e")
スナップショットディレクトリをバージョン管理に追加します:
tests/testthat/_snaps/ # コミット済み — 期待値を含む
期待結果: スナップショットファイルがリグレッション検出のためにgitでトラッキングされています。
失敗時: スナップショットが予期せず変更された場合は、testthat::snapshot_review()を実行して差分を確認してください。意図的な変更はtestthat::snapshot_accept()で受け入れてください。
ステップ6: CIとの統合
.github/workflows/R-CMD-check.yamlに追加するか、専用のワークフローを作成します:
- name: Install system dependencies
run: |
sudo apt-get update
sudo apt-get install -y chromium-browser
- name: Set Chrome path
run: echo "CHROMOTE_CHROME=$(which chromium-browser)" >> $GITHUB_ENV
- name: Run tests
run: |
Rscript -e 'devtools::test()'
golemアプリの場合は、テスト前にアプリパッケージがインストールされていることを確認してください:
- name: Install app package
run: Rscript -e 'devtools::install()'
期待結果: ヘッドレスChromeでCIのテストが通過します。
失敗時: よくあるCIの問題:Chromeがインストールされていない(apt-getステップを追加)、タイムアウト(AppDriver$new()のtimeoutを増やす)。
バリデーション
-
devtools::test()がすべてのテストをエラーなしで実行する - testServer()テストがモジュールサーバーロジックをカバーする
- shinytest2テストが主要なユーザーワークフローをカバーする
- スナップショットファイルがバージョン管理にコミットされている
- CI環境でテストが通過する
- エッジケースがテストされている(空のデータ、NULL入力、エラー状態)
よくある落とし穴
- ロジックではなくUIレンダリングをテストする: ロジックには
testServer()を、データにはapp$expect_values()を優先してください。視覚的な外観が重要な場合にのみapp$expect_screenshot()を使用してください — スクリーンショットはプラットフォーム間で壊れやすいです。 - e2eテストでのモジュールID形式: AppDriver経由でモジュールの入力を設定するときは、
"moduleId.inputId"ではなく"moduleId-inputId"形式(ハイフン区切り)を使用してください。 - タイミングの不安定さ:
app$set_inputs()の後は常にapp$wait_for_idle()を呼び出してください。それなしではリアクティブな更新が完了する前にアサーションが実行される可能性があります。 - スナップショットのドリフト: 異なるプラットフォーム(MacとLinux)で生成されたスナップショットをコミットしないでください。スナップショット生成はCIプラットフォームに標準化してください。
- CIでChromeがない: shinytest2はChrome/Chromiumが必要です。CIワークフローには常にインストールステップを含めてください。
関連スキル
build-shiny-module— 明確なインターフェースを持つテスト可能なモジュールの作成scaffold-shiny-app— テストインフラを含むアプリ構造のセットアップwrite-testthat-tests— Rパッケージの一般的なtestthatパターンsetup-github-actions-ci— Rパッケージ(golemアプリ)のCI/CDセットアップ
GitHub 저장소
연관 스킬
evaluating-llms-harness
테스팅이 Claude Skill은 MMLU, GSM8K를 포함한 60개 이상의 표준화된 학술 과제에서 LLM 성능을 벤치마크하기 위해 lm-evaluation-harness를 실행합니다. 개발자들이 모델 품질을 비교하고, 학습 진행 상황을 추적하거나 학술 결과를 보고할 수 있도록 설계되었습니다. 이 도구는 HuggingFace와 vLLM 모델을 포함한 다양한 백엔드를 지원합니다.
cloudflare-cron-triggers
테스팅이 스킬은 cron 표현식을 사용하여 Worker를 스케줄링하기 위한 Cloudflare Cron Triggers 구현에 관한 포괄적인 지식을 제공합니다. 주기적 작업, 유지보수 작업, 자동화된 워크플로우 설정 방법을 다루며, 잘못된 cron 표현식이나 시간대 문제 같은 일반적인 이슈들을 해결하는 방법을 포함합니다. 개발자들은 이를 통해 스케줄된 핸들러 구성, cron 트리거 테스트, Workflows 및 Green Compute와의 연동 작업을 수행할 수 있습니다.
webapp-testing
테스팅이 Claude Skill은 Python 스크립트를 통해 로컬 웹 애플리케이션을 테스트하기 위한 Playwright 기반 툴킷을 제공합니다. 프론트엔드 검증, UI 디버깅, 스크린샷 캡처, 로그 확인 기능을 지원하며 서버 라이프사이클을 관리합니다. 브라우저 자동화 작업에 사용하되 컨텍스트 오염을 방지하기 위해 소스 코드를 읽지 않고 스크립트를 직접 실행하세요.
finishing-a-development-branch
테스팅이 스킬은 테스트 통과를 확인한 후 체계적인 통합 옵션을 제시하여 개발자가 완성된 작업을 마무리하도록 돕습니다. 구현이 완료된 후 머지, PR 생성, 브랜치 정리와 같은 워크플로우를 안내합니다. 코드가 준비되고 테스트가 완료되었을 때 개발 프로세스를 체계적으로 마무리하기 위해 사용하세요.
