协作头脑风暴
brainstorming
在实现前澄清需求、探索设计选择,并形成清晰的开发方向。
test-shiny-app【开发与工程】Test Shiny applications using shinytest2 for end-to-end browser tests and testServer() for unit-testing module server logic. Covers snapshot testing, CI integration, and mocking external services. Use when adding tests to an existing Shiny application, setting up a testing strategy for a new Shiny project, writing regression tests before refactoring …
独立 GitHub 快照 · 自动分类 · 以原作者文档为准
以 shinytest2(端對端)與 testServer()(單元測試)為 Shiny 應用設立全面測試。
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)
預期: shinytest2 已裝且 testthat 目錄結構就位。
失敗時: shinytest2 需 chromote(無頭 Chrome)。於系統裝 Chrome/Chromium。WSL 上:sudo apt install -y chromium-browser。以 chromote::find_chrome() 驗。
建 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"))
})
})
關鍵模式:
testServer() 無瀏覽器測模組伺服器邏輯args 列表傳反應參數session$setInputs() 模擬用戶互動預期: 模組測試以 devtools::test() 通過。
失敗時: 若 testServer() 報錯「不為模組伺服器函式」,確保函式內部用 moduleServer()。若 session$setInputs() 不觸發反應,於設輸入後加 session$flushReact()。
建 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")
})
關鍵模式:
AppDriver$new() 於無頭 Chrome 啟應用on.exit(app$stop()) 清理"moduleId-inputId" 格式app$expect_values() 建/比對快照檔app$wait_for_idle() 確反應更新完成預期: 端對端測試於 tests/testthat/_snaps/ 建快照檔。
失敗時: 若找不到 Chrome,將 CHROMOTE_CHROME 環境變數設為 Chrome 二進位之路徑。若快照於 CI 失敗而本機過,檢平台依賴之渲染差——對資料快照用 app$expect_values(),而非對視覺者用 app$expect_screenshot()。
shinytest2::record_test("path/to/app")
此於含錄製面板之瀏覽器中開應用。與應用互動,再點「Save test」自動產生測試碼。
預期: 一測試文件於 tests/testthat/ 中產生,含所錄互動。
失敗時: 若錄製器不開,先檢應用以 shiny::runApp() 成功執。錄製器需可運作之應用。
對快照測試,管理預期值:
# Accept new/changed snapshots after review
testthat::snapshot_accept("test-app-e2e")
# Review snapshot differences
testthat::snapshot_review("test-app-e2e")
將快照目錄加入版本控制:
tests/testthat/_snaps/ # Committed — contains expected values
預期: 快照檔於 git 中追蹤以供回歸偵測。
失敗時: 若快照意外變化,跑 testthat::snapshot_review() 看差。以 testthat::snapshot_accept() 接受意圖之變。
加入 .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()'
預期: 測試於 CI 中以無頭 Chrome 通過。
失敗時: 常見 CI 問題:Chrome 未裝(加 apt-get 步驟)、顯示伺服器缺(shinytest2 預設用無頭模式故通常非問題)、慢執行器逾時(增 AppDriver$new() 之 timeout)。
devtools::test() 無錯執所有測試testServer(),資料用 app$expect_values()。僅當視覺外觀重要時用 app$expect_screenshot()——截圖跨平台脆弱。"moduleId-inputId" 格式(連字符分隔),非 "moduleId.inputId"。app$set_inputs() 後叫 app$wait_for_idle()。否則斷言可能於反應更新完成前執。build-shiny-module — 建可測之具清晰介面之模組scaffold-shiny-app — 設立含測試基礎建設之應用結構write-testthat-tests — R 套件之一般 testthat 模式setup-github-actions-ci — R 套件(golem 應用)之 CI/CD 設立