【问题标题】:How to test a function with a combination of parameters without resorting to a for loop如何在不使用 for 循环的情况下使用参数组合测试函数
【发布时间】:2022-01-30 13:08:00
【问题描述】:

在 R 中,是否可以在不使用 for 循环的情况下测试具有参数组合的函数?例如,我目前正在做类似的事情:

test_that("Function myfunction() works properly", {

  a1 <- c(1, 2, 3, 10, 20, 100)
  a2 <- c(-500, 0, 500)
  a3 <- c("hello", "world")

  for (a1i in a1) {
    for (a2i in a2) {
      for (a3i in a3) {

        result <- myfunction(a1i, a2i, a3i)
        expect_equal(result, something_expected)
        expect_equal(dim(result), something_else)
        # ...and other checks...

      }
    }
  }
})

但是,对于太多的嵌套 fors,这并不实用,并且还会引发 lintr 的圈复杂度错误。

在 Python 中,我们可以使用 pytest(使用测试参数或文本夹具)轻松地做到这一点,这在 Julia 中也很容易实现。

找到了patrick这个包,但是好像没有这种方式做参数组合,只是定义参数集。我想可以使用 for 循环为 patrick 创建这些参数集,但这似乎没有抓住重点。

【问题讨论】:

    标签: r unit-testing testthat


    【解决方案1】:

    如果你想完全避免for 循环,那么你可以使用包purrr 的映射函数来迭代数据帧,这是由expand.grid 产生的:

    a1 <- c(1, 2, 3, 10, 20, 100)
    a2 <- c(-500, 0, 500)
    a3 <- c("hello", "world")
    
    df <- expand.grid(a1,a2,a3, stringsAsFactors = FALSE) 
    
    # purrr::pwalk(df, ~ cat(..1, ..2, ..3, "\n")) <-- avoiding for loop
    
    for (i in 1:nrow(df))
      cat(df[i,1], df[i, 2], df[i, 3], "\n")
    #> 1 -500 hello 
    #> 2 -500 hello 
    #> 3 -500 hello 
    #> 10 -500 hello 
    #> 20 -500 hello 
    #> 100 -500 hello 
    #> 1 0 hello 
    #> 2 0 hello 
    #> 3 0 hello 
    #> 10 0 hello 
    #> 20 0 hello 
    #> 100 0 hello 
    #> 1 500 hello 
    #> 2 500 hello 
    #> 3 500 hello 
    #> 10 500 hello 
    #> 20 500 hello 
    #> 100 500 hello 
    #> 1 -500 world 
    #> 2 -500 world 
    #> 3 -500 world 
    #> 10 -500 world 
    #> 20 -500 world 
    #> 100 -500 world 
    #> 1 0 world 
    #> 2 0 world 
    #> 3 0 world 
    #> 10 0 world 
    #> 20 0 world 
    #> 100 0 world 
    #> 1 500 world 
    #> 2 500 world 
    #> 3 500 world 
    #> 10 500 world 
    #> 20 500 world 
    #> 100 500 world
    

    【讨论】:

    • 我希望有一些集成或扩展的测试,但事实是你的建议有效。我去了 expand.grid 以最小化依赖关系。不知道。谢谢。
    • 欢迎您,@faken!
    【解决方案2】:

    这是一个使用基数 R 的可能选项(如果您想避免 for 循环也可以),但在 @Paulsmith 上使用 expand.grid

    invisible(apply(df, 1, function(x){
        cat(paste0(paste(x[1],x[2],x[3],sep=' '),"\n"))
      }))
    

    输出

      1 -500 hello
      2 -500 hello
      3 -500 hello
     10 -500 hello
     20 -500 hello
    100 -500 hello
      1    0 hello
      2    0 hello
      3    0 hello
     10    0 hello
     20    0 hello
    100    0 hello
      1  500 hello
      2  500 hello
      3  500 hello
     10  500 hello
     20  500 hello
    100  500 hello
      1 -500 world
      2 -500 world
      3 -500 world
     10 -500 world
     20 -500 world
    100 -500 world
      1    0 world
      2    0 world
      3    0 world
     10    0 world
     20    0 world
    100    0 world
      1  500 world
      2  500 world
      3  500 world
     10  500 world
     20  500 world
    100  500 world
    

    数据

    a1 <- c(1, 2, 3, 10, 20, 100)
    a2 <- c(-500, 0, 500)
    a3 <- c("hello", "world")
    
    df <- expand.grid(a1,a2,a3, stringsAsFactors = FALSE) 
    

    【讨论】:

      猜你喜欢
      • 2023-02-05
      • 1970-01-01
      • 2020-02-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-03-29
      • 1970-01-01
      • 2011-02-22
      相关资源
      最近更新 更多