【问题标题】:Testing modular R Shiny (golem) dashboards测试模块化 R Shiny (golem) 仪表板
【发布时间】:2021-05-14 08:29:48
【问题描述】:

我一直在探索(**并且喜欢)使用 R Shiny 开发模块化仪表板的 golem 包。但是我正在努力思考如何测试模块化仪表板。

例如,在下面的 repex 中,如果导入模块中的 input$n_rows 设置为 15,我将如何测试显示模块中的输出包含 15 行?

如果您对此提供任何支持,我将不胜感激!


library(shiny)
library(reactable)
library(dplyr)

# Import module UI
mod_import_ui <- function(id){
  
  ns <- NS(id)
  
  fluidRow(
    # Allow the user to select the number of rows to view
    numericInput(ns("n_rows"), 
                 "Select number of observations",
                 value = 10)
    
  )
}

# Import module Server
mod_import_server <- function(id){
  
  moduleServer(
    id,
    function(input, output, session){
      
      data <- reactive({
        
        # Sample the requested number of rows from mtcars and return this to the application server
        mtcars %>%
          slice_sample(n = input$n_rows)
        # [....] # Some complex formatting and transformations
        
      })
      
      return(data)
      
      
      
    }
  )}

# Display module UI
mod_display_ui <- function(id){
  
  ns <- NS(id)
  
  fluidRow(
    
    reactableOutput(ns("table"))
    
  )
}

# Display module Server
mod_display_server <- function(id, data_in){
  
  moduleServer(
    id,
    function(input, output, session){
      
      # [....] # Some more transformations and merging with data from other modules
      
      output$table <- renderReactable(reactable(data_in()))
      
    }
  )}


app_ui <- function(request) { 
  
  tagList(
  
    mod_import_ui("import_1"),
    mod_display_ui("display_1")

  )
  
  }


app_server <- function(input, output, session) { 
  
  data_in <- mod_import_server("import_1")
  mod_display_server("display_1", data_in)
  
}

shinyApp(ui = app_ui, server = app_server)


【问题讨论】:

    标签: r shiny golem


    【解决方案1】:

    我建议将应用程序的核心与用户界面分开。

    {golem} 框架允许在 R 包中构建您的应用程序,这意味着您可以使用从包构建到记录和测试代码的所有工具。
    如果您按照engineering-shiny.org/ 中的指南进行操作,您将看到我们建议从“服务器”部分提取所有 R 代码以在小插图中对其进行测试,将其转换为常规函数,以便您可以像往常一样使用 R 进行测试包。
    因此,您 ShinyApp 只调用已经记录和测试的内部函数。使用这种方法,您可以测试应用程序中可能发生的不同场景的输出。在静态脚本中尝试不同的输入参数并验证输出,无论您在后续开发步骤中对应用程序进行了哪些更改。

    这本书提供了很多建议。如果我必须将它们总结为一个工作流程,这将是:

    1. 直接在 Rmd 中构建必要的代码。这使您无需进行所有必要的点击即可测试操作。我们称之为“Rmd first”方法:https://rtask.thinkr.fr/when-development-starts-with-documentation/
    2. 将此代码分解为 R 函数,以尽可能少地放入 Shiny 应用程序本身。
    3. 在没有服务器的情况下创建您的 UI 部分(或不要太多),只是为了看看总体外观是什么样的
    4. 将您的函数包含在应用程序的适当位置。
    5. 加强代码。可重现的示例、单元测试、文档、代码版本控制……(与代码并行执行此步骤会更好)

    【讨论】:

    • 谢谢你!我有点不确定如何在函数中包含反应性或反应性值(在 R Shiny 会话之外运行)。但是我想您可以将输入包装在一个函数中(对于反应式)或构建一个列表(对于反应式)。再次感谢! # 带有反应式trim_data &lt;- function(data, num) { data() %&gt;% slice_sample(n = num) } get_mt &lt;- function(){mtcars} trim_data(get_mt, 12) # With reactivevals trim_data2 &lt;- function(r, num) { r$data %&gt;% slice_sample(n = num) } r &lt;- list(data = mtcars) trim_data2(r, 12)
    【解决方案2】:

    作为对 Sebastien 回答的补充,我想指出,从 {shiny} v 1.5.0 开始,您可以直接使用 testServer 函数测试服务器功能,这可能是您正在寻找的。

    以下是您如何实现这一目标的代表:

    library(shiny)
    library(magrittr)
    library(dplyr)
    
    mod_import_server <- function(id){
      moduleServer( id, function(input, output, session){
        data <- reactive({
          mtcars %>%
            slice(n = 1:input$n_rows)
        })
        return(data)
      })
    }
    
    shiny::testServer(mod_import_server, {
      
      for (i in 1:10){
        
        session$setInputs(n_rows = i)
        testthat::expect_equal(
          data(), 
          slice(mtcars, n = 1:i)
        )
        
      }
    })
    

    在这里,您可以测试您的reactive() 的行为是否符合您的预期。 这并不完美,但一个好的开始:) 但是,很难找到一种方法来测试第二个模块的行为,因为它依赖于作为值传递的 reactive()。

    科林

    【讨论】:

    • 干杯科林!这真的很有帮助。
    猜你喜欢
    • 1970-01-01
    • 2021-01-31
    • 2020-07-09
    • 2023-04-08
    • 2019-04-28
    • 2017-09-27
    • 2015-07-07
    • 1970-01-01
    • 2023-02-07
    相关资源
    最近更新 更多