协作头脑风暴
brainstorming
在实现前澄清需求、探索设计选择,并形成清晰的开发方向。
test-shiny-app【开发与工程】Probar aplicaciones Shiny usando shinytest2 para tests de navegador de extremo a extremo y testServer() para tests unitarios de la lógica del server de módulos. Cubre pruebas de snapshot, integración con CI y simulación de servicios externos. Úsalo al añadir tests a una aplicación Shiny existente, al configurar una estrategia de tests para un nuevo p…
独立 GitHub 快照 · 自动分类 · 以原作者文档为准
Configurar tests completos para aplicaciones Shiny usando shinytest2 (extremo a extremo) y testServer() (tests unitarios).
install.packages("shinytest2")
# For golem apps, add as a Suggests dependency
usethis::use_package("shinytest2", type = "Suggests")
# Set up testthat infrastructure if not present
usethis::use_testthat(edition = 3)
Esperado: shinytest2 instalado y estructura de directorios testthat en su lugar.
En caso de fallo: shinytest2 requiere chromote (Chrome sin cabeza). Instala Chrome/Chromium en el sistema. En WSL: sudo apt install -y chromium-browser. Verifica con chromote::find_chrome().
Crea 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")
), {
# Set inputs
session$setInputs(column = "Species")
session$setInputs(value_select = "setosa")
session$setInputs(apply = 1)
# Check output
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")
), {
# Module should not error on empty data
expect_no_error(session$setInputs(column = "Species"))
})
})
Patrones clave:
testServer() prueba la lógica del server del módulo sin un navegadorargssession$setInputs() para simular interacciones del usuarioEsperado: Los tests del módulo pasan con devtools::test().
En caso de fallo: Si testServer() da error con "not a module server function", asegúrate de que la función use moduleServer() internamente. Si session$setInputs() no activa los reactivos, añade session$flushReact() después de establecer las entradas.
Crea tests/testthat/test-app-e2e.R:
test_that("app loads and displays initial state", {
# For golem apps
app <- AppDriver$new(
app_dir = system.file(package = "myapp"),
name = "initial-load",
height = 800,
width = 1200
)
on.exit(app$stop(), add = TRUE)
# Wait for app to load
app$wait_for_idle(timeout = 10000)
# Check that key elements exist
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)
# Interact with the app
app$set_inputs(`filter1-column` = "cyl")
app$wait_for_idle()
app$set_inputs(`filter1-apply` = "click")
app$wait_for_idle()
# Snapshot the output values
app$expect_values(output = "table")
})
Patrones clave:
AppDriver$new() lanza la app en Chrome sin cabezaon.exit(app$stop()) para limpiar"moduleId-inputId"app$expect_values() crea/compara archivos de snapshotapp$wait_for_idle() garantiza que las actualizaciones reactivas completenEsperado: Los tests de extremo a extremo crean archivos de snapshot en tests/testthat/_snaps/.
En caso de fallo: Si Chrome no se encuentra, establece la variable de entorno CHROMOTE_CHROME a la ruta del binario de Chrome. Si los snapshots fallan en CI pero pasan en local, verifica las diferencias de renderizado dependientes de la plataforma — usa app$expect_values() para snapshots de datos en lugar de app$expect_screenshot() para snapshots visuales.
shinytest2::record_test("path/to/app")
Esto abre la app en un navegador con un panel de grabación. Interactúa con la app, luego haz clic en "Save test" para generar automáticamente el código del test.
Esperado: Un archivo de test generado en tests/testthat/ con las interacciones grabadas.
En caso de fallo: Si la grabadora no abre, verifica que la app se ejecute exitosamente con shiny::runApp() primero. La grabadora requiere una app funcional.
Para tests basados en snapshots, gestiona los valores esperados:
# Accept new/changed snapshots after review
testthat::snapshot_accept("test-app-e2e")
# Review snapshot differences
testthat::snapshot_review("test-app-e2e")
Añade los directorios de snapshots al control de versiones:
tests/testthat/_snaps/ # Confirmado — contiene los valores esperados
Esperado: Archivos de snapshot rastreados en git para detección de regresiones.
En caso de fallo: Si los snapshots cambian inesperadamente, ejecuta testthat::snapshot_review() para ver las diferencias. Acepta los cambios intencionales con testthat::snapshot_accept().
Añade a .github/workflows/R-CMD-check.yaml o crea un workflow dedicado:
- 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()'
Para apps golem, asegúrate de que el paquete de la app esté instalado antes de las pruebas:
- name: Install app package
run: Rscript -e 'devtools::install()'
Esperado: Los tests pasan en CI con Chrome sin cabeza.
En caso de fallo: Problemas comunes de CI: Chrome no instalado (añade el paso apt-get), servidor de visualización faltante (shinytest2 usa modo sin cabeza por defecto, por lo que normalmente no es un problema), o tiempo de espera excedido en runners lentos (aumenta timeout en AppDriver$new()).
devtools::test() ejecuta todos los tests sin errorestestServer() para la lógica y app$expect_values() para los datos. Solo usa app$expect_screenshot() cuando la apariencia visual importa — los screenshots son frágiles entre plataformas."moduleId-inputId" (separado por guión), no "moduleId.inputId".app$wait_for_idle() después de app$set_inputs(). Sin esto, las aserciones pueden ejecutarse antes de que las actualizaciones reactivas completen.build-shiny-module — crear módulos comprobables con interfaces clarasscaffold-shiny-app — configurar la estructura de la app con infraestructura de testswrite-testthat-tests — patrones generales de testthat para paquetes Rsetup-github-actions-ci — configuración CI/CD para paquetes R (apps golem)