test-shiny-app
关于
This skill helps developers test Shiny applications using shinytest2 for end-to-end UI testing and testServer() for unit testing server logic. It covers snapshot testing, UI interaction tests, module testing, and CI/CD integration. Use it to validate app behavior, set up regression tests, or incorporate testing into your deployment pipeline.
快速安装
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-app在 Claude Code 中复制并粘贴此命令以安装该技能
技能文档
name: test-shiny-app description: > Shiny-Anwendungen mit shinytest2 für End-to-End-Tests und testServer() für Unit-Tests der Server-Logik testen. Behandelt Snapshot-Tests, UI-Interaktionstests, Modul-Unit-Tests und CI-Integration. Verwenden, wenn Shiny-App-Verhalten validiert, Regressionstests eingerichtet oder Tests in CI/CD eingebunden werden sollen. license: MIT locale: de source_locale: en source_commit: 6f65f316 translator: claude-opus-4-6 translation_date: 2026-03-16 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, testthat, ci-cd
Shiny-App testen
Shiny-Anwendungen mit shinytest2 (End-to-End) und testServer() (Unit-Tests) zuverlässig testen.
Wann verwenden
- Shiny-App-Verhalten vor dem Deployment validieren
- Regressionstests für kritische User Journeys einrichten
- Modul-Logik isoliert unit-testen
- Shiny-Tests in GitHub Actions CI einbinden
Eingaben
- Erforderlich: Laufende Shiny-App (lokal oder remote)
- Optional: Bestehende
tests/-Verzeichnisstruktur - Optional: CI-Workflow für automatische Testausführung
Vorgehensweise
Schritt 1: shinytest2 installieren
shinytest2 und seine Dependencies installieren.
install.packages("shinytest2")
# Chromium-Browser für UI-Tests installieren (benötigt Netzwerkzugriff)
shinytest2::install_chromium()
# Für CI (headless Chrome verwenden)
# Chromium wird über chromote automatisch gefunden
In bestehende Teststruktur integrieren:
# Tests-Verzeichnis einrichten (wenn noch nicht vorhanden)
usethis::use_testthat()
# shinytest2 in Testinfrastruktur integrieren
shinytest2::use_shinytest2()
Erwartet: shinytest2 installiert. tests/testthat/setup-shinytest2.R erstellt.
Bei Fehler: Wenn Chromium-Installation fehlschlägt, systemweit installierten Chrome/Chromium verwenden: shinytest2::install_chromium(force = TRUE).
Schritt 2: Ersten Snapshot-Test erstellen
shinytest2 im Record-Modus verwenden, um Test-Snapshots automatisch zu generieren.
# Aufzeichnung starten (öffnet App + Test-Recorder)
shinytest2::record_test(".")
# Alternativ: Manuell ersten Test schreiben
# tests/testthat/test-app.R
Aufgezeichnete Tests sehen aus wie:
# tests/testthat/test-app.R
library(shinytest2)
test_that("app startet und UI rendert korrekt", {
app <- AppDriver$new(
app_dir = system.file(package = "myapp"), # oder "."
name = "app-startup-test"
)
# Anfangs-Screenshot aufnehmen
app$expect_screenshot()
app$stop()
})
Erwartet: Snapshot-Bilder in tests/testthat/_snaps/ erstellt. Test läuft ohne Fehler.
Bei Fehler: Wenn App nicht startet, Konsolen-Output mit app$get_logs() prüfen. Wenn Screenshot-Vergleich fehlschlägt, Snapshots mit shinytest2::snapshot_review() aktualisieren.
Schritt 3: UI-Interaktionstests schreiben
Tests für spezifisches User-Verhalten schreiben.
# tests/testthat/test-interactions.R
library(shinytest2)
test_that("Datensatz-Auswahl aktualisiert Tabelle", {
app <- AppDriver$new(".", name = "dataset-selection")
# Initialen Zustand prüfen
initial_value <- app$get_value(output = "table")
expect_true(length(initial_value$body) > 0)
# Input ändern
app$set_inputs(dataset = "mtcars")
app$expect_values(output = "table")
app$stop()
})
test_that("Slider filtert Zeilenanzahl", {
app <- AppDriver$new(".", name = "slider-filter")
app$set_inputs(n_rows = 5)
app$click("apply")
# Wert aus Output extrahieren und prüfen
table_data <- app$get_value(output = "table")
expect_equal(nrow(table_data$body), 5)
app$stop()
})
Erwartet: Tests simulieren User-Interaktionen und prüfen Output-Änderungen.
Bei Fehler: Wenn get_value() unerwartete Struktur zurückgibt, app$get_value(output = "table") |> str() verwenden, um die tatsächliche Struktur zu untersuchen.
Schritt 4: Server-Logik unit-testen
Shiny-Server-Funktionen mit testServer() isoliert testen.
# tests/testthat/test-server.R
library(shiny)
library(testthat)
test_that("server berechnet korrekten Mittelwert", {
testServer(app_server, {
# Inputs setzen
session$setInputs(dataset = "iris", n_rows = 10)
# Output prüfen
expect_s3_class(output$table$result, "data.frame")
expect_equal(nrow(output$table$result), 10)
})
})
test_that("reactive Werte aktualisieren korrekt", {
testServer(app_server, {
session$setInputs(multiplier = 2)
# Reaktiven Wert prüfen
result <- filtered_data()
expect_true(all(result$value > 0))
})
})
Für Modul-Tests:
# tests/testthat/test-mod_data_filter.R
test_that("data filter Modul filtert korrekt", {
test_data <- reactive({ head(iris, 100) })
testServer(
mod_data_filter_server,
args = list(data = test_data),
{
session$setInputs(n_rows = 5, apply = 1)
result <- session$returned()
expect_equal(nrow(result()), 5)
}
)
})
Erwartet: Server-Logik unabhängig von UI testbar. Reaktive Berechnungen verifizierbar.
Bei Fehler: Wenn testServer() fehlschlägt mit "could not find function", sicherstellen, dass Server-Funktion exportiert oder im Paket-Namespace zugänglich ist.
Schritt 5: Edge Cases und Fehlerbehandlung testen
Randfälle und Fehlerszenarien testen.
# tests/testthat/test-edge-cases.R
test_that("app behandelt leere Eingaben korrekt", {
testServer(app_server, {
session$setInputs(dataset = NULL, n_rows = 0)
# Sicherstellen dass App nicht abstürzt
expect_silent(output$table)
})
})
test_that("app zeigt Fehlermeldung bei ungültigen Eingaben", {
app <- AppDriver$new(".", name = "error-handling")
# Ungültige Eingabe erzwingen (z. B. via URL-Parameter)
app$set_inputs(n_rows = -1)
app$click("apply")
# Fehlermeldung prüfen
error_output <- app$get_value(output = "error_message")
expect_false(is.null(error_output))
app$stop()
})
Erwartet: App behandelt edge cases ohne Absturz. Fehlermeldungen korrekt angezeigt.
Bei Fehler: Wenn Tests edge cases nicht abdecken, Fehlerbehandlung im Server mit tryCatch() oder validate(need(...)) hinzufügen.
Schritt 6: CI-Integration
Tests in GitHub Actions CI einbinden.
# .github/workflows/test-shiny.yml
name: Shiny Tests
on:
push:
branches: [main]
pull_request:
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: r-lib/actions/setup-r@v2
with:
use-public-rspm: true
- name: Install system dependencies
run: |
sudo apt-get install -y chromium-browser
- uses: r-lib/actions/setup-r-dependencies@v2
with:
extra-packages: shinytest2, testthat
- name: Run tests
run: |
Rscript -e "testthat::test_dir('tests/testthat')"
env:
CHROMOTE_CHROME_ARGS: "--no-sandbox" # Für CI erforderlich
Erwartet: Tests in CI auf Push/PR ausgeführt. Fehlgeschlagene Tests blockieren Merge.
Bei Fehler: Wenn Chromium in CI nicht gefunden wird, CHROMOTE_CHROME_ARGS="--no-sandbox --disable-gpu" und sicherstellen, dass chromium-browser oder google-chrome installiert ist.
Validierung
- shinytest2 installiert und Chromium verfügbar
- Snapshots in
tests/testthat/_snaps/erstellt - UI-Interaktionstests simulieren echte User-Workflows
- Server-Unit-Tests via
testServer()prüfen Logik isoliert - Edge Cases und Fehlerbehandlung getestet
- Tests in CI laufen ohne Fehler
Haeufige Stolperfallen
- Nicht-deterministische Snapshots: Animationen, Timestamps oder zufällige Daten verursachen Snapshot-Instabilität.
set.seed()verwenden und dynamischen Inhalt mocken. - Chromium fehlt in CI: Immer
--no-sandbox-Flag in CI-Umgebungen setzen. GitHub Actions braucht spezielle Chromium-Konfiguration. testServer()vsAppDriver:testServer()testet Server-Logik isoliert (keine echten UI).AppDrivertestet echte Browser-Interaktionen.- Veraltete Snapshots: Nach UI-Änderungen müssen Snapshots mit
shinytest2::snapshot_review()odershinytest2::snapshot_update()aktualisiert werden. - Timing-Probleme: Asynchrone Operationen (Plots, Downloads) benötigen
app$wait_for_idle()nach auslösenden Aktionen. - Modul-Tests ohne Reaktivität:
testServer()benötigt reaktive Inputs — immersession$setInputs()vor Assertions aufrufen.
Verwandte Skills
scaffold-shiny-app— Shiny-App vor dem Testen scaffoldenbuild-shiny-module— Module erstellen, die mittestServer()getestet werdendeploy-shiny-app— Getestete App deployensetup-github-actions-ci— CI/CD-Workflows einrichten
GitHub 仓库
相关推荐技能
evaluating-llms-harness
测试该Skill通过60+个学术基准测试(如MMLU、GSM8K等)评估大语言模型质量,适用于模型对比、学术研究及训练进度追踪。它支持HuggingFace、vLLM和API接口,被EleutherAI等行业领先机构广泛采用。开发者可通过简单命令行快速对模型进行多任务批量评估。
cloudflare-cron-triggers
测试这个Claude Skill提供了关于Cloudflare Cron Triggers的完整知识库,用于通过cron表达式定时执行Workers。它支持配置周期性任务、维护作业和自动化工作流,并能处理常见的cron触发错误。开发者可以用它来设置定时任务、测试cron处理器,并集成Workflows和Green Compute功能。
webapp-testing
测试该Skill为开发者提供了基于Playwright的本地Web应用测试工具集,支持自动化测试前端功能、调试UI行为、捕获屏幕截图和查看浏览器日志。它包含管理服务器生命周期的辅助脚本,可直接作为黑盒工具运行而无需阅读源码。适用于需要快速验证本地Web应用界面和交互功能的开发场景。
finishing-a-development-branch
测试这个Skill用于开发分支完成后的集成决策,当代码实现完成且测试通过时,它会引导开发者选择合适的工作流。它首先验证测试状态,然后提供合并、创建PR或清理等结构化选项。核心价值在于确保代码质量的同时,标准化分支收尾流程。
