是否有用于比较两个对象行为的 expect_* 函数测试?
Is there a testthat expect_* function for comparing two objects behavior?
我正在使用 testthat
为 R 包编写一些单元测试。我想比较两个对象,其中并非所有细节都需要匹配,但它们必须在一组感兴趣的函数方面保持等价。
举个简单的例子,我想用
library(testthat)
x <- 1:4
y <- matrix(4:1, nrow=2)
test_that("objects behave similarly", {
expect_equal_applied(x, y, .fn=list(sum, prod))
## which would be shorthand for:
## expect_equal(sum(x), sum(y))
## expect_equal(prod(x), prod(y))
})
实际上,x
和 y
可能是 S3 对象,而不仅仅是基础数据结构。
显然,这很容易实现,但如果已经存在,我更喜欢惯用的东西。所以,问题是,testthat
是否实现了这样的 expect 函数?
通过 API 搜索,我觉得没有什么符合这个描述,但它似乎是一个自然的模式。或者也许有一个原因让我忽略了这种模式令人反感的原因。
查看 documentation {testthat} 目前(第三版)没有像 expect_equal_applied
那样的功能。但是,正如你已经提到的,我们可以很容易地构造这样一个函数:
library(testthat)
x <- 1:4
y <- matrix(4:1, nrow=2)
expect_equal_applied <- function(object, expected, fns) {
fns <- purrr::map(fns, rlang::as_function)
purrr::map(fns, ~ expect_equal(.x(object), .x(expected)))
}
test_that("objects behave similarly", {
expect_equal_applied(x, y, fns = list(sum, prod))
})
#> Test passed
x <- 1:3
test_that("objects behave similarly", {
expect_equal_applied(x, y, fns = list(sum, prod))
})
#> -- Failure (<text>:19:3): objects behave similarly -----------------------------
#> .x(object) not equal to .x(expected).
#> 1/1 mismatches
#> [1] 6 - 10 == -4
#> Backtrace:
#> 1. global::expect_equal_applied(x, y, fns = list(sum, prod))
#> 2. purrr::map(fns, ~expect_equal(.x(object), .x(expected)))
#> 3. .f(.x[[i]], ...)
#> 4. testthat::expect_equal(.x(object), .x(expected))
#>
#> -- Failure (<text>:19:3): objects behave similarly -----------------------------
#> .x(object) not equal to .x(expected).
#> 1/1 mismatches
#> [1] 6 - 24 == -18
#> Backtrace:
#> 1. global::expect_equal_applied(x, y, fns = list(sum, prod))
#> 2. purrr::map(fns, ~expect_equal(.x(object), .x(expected)))
#> 3. .f(.x[[i]], ...)
#> 4. testthat::expect_equal(.x(object), .x(expected))
由 reprex package (v2.0.1)
于 2021-09-17 创建
关于为什么在{testthat}中似乎缺少这样的功能,我认为这不是真正必要的,我们可以用lapply
或map
构造它。
我正在使用 testthat
为 R 包编写一些单元测试。我想比较两个对象,其中并非所有细节都需要匹配,但它们必须在一组感兴趣的函数方面保持等价。
举个简单的例子,我想用
library(testthat)
x <- 1:4
y <- matrix(4:1, nrow=2)
test_that("objects behave similarly", {
expect_equal_applied(x, y, .fn=list(sum, prod))
## which would be shorthand for:
## expect_equal(sum(x), sum(y))
## expect_equal(prod(x), prod(y))
})
实际上,x
和 y
可能是 S3 对象,而不仅仅是基础数据结构。
显然,这很容易实现,但如果已经存在,我更喜欢惯用的东西。所以,问题是,testthat
是否实现了这样的 expect 函数?
通过 API 搜索,我觉得没有什么符合这个描述,但它似乎是一个自然的模式。或者也许有一个原因让我忽略了这种模式令人反感的原因。
查看 documentation {testthat} 目前(第三版)没有像 expect_equal_applied
那样的功能。但是,正如你已经提到的,我们可以很容易地构造这样一个函数:
library(testthat)
x <- 1:4
y <- matrix(4:1, nrow=2)
expect_equal_applied <- function(object, expected, fns) {
fns <- purrr::map(fns, rlang::as_function)
purrr::map(fns, ~ expect_equal(.x(object), .x(expected)))
}
test_that("objects behave similarly", {
expect_equal_applied(x, y, fns = list(sum, prod))
})
#> Test passed
x <- 1:3
test_that("objects behave similarly", {
expect_equal_applied(x, y, fns = list(sum, prod))
})
#> -- Failure (<text>:19:3): objects behave similarly -----------------------------
#> .x(object) not equal to .x(expected).
#> 1/1 mismatches
#> [1] 6 - 10 == -4
#> Backtrace:
#> 1. global::expect_equal_applied(x, y, fns = list(sum, prod))
#> 2. purrr::map(fns, ~expect_equal(.x(object), .x(expected)))
#> 3. .f(.x[[i]], ...)
#> 4. testthat::expect_equal(.x(object), .x(expected))
#>
#> -- Failure (<text>:19:3): objects behave similarly -----------------------------
#> .x(object) not equal to .x(expected).
#> 1/1 mismatches
#> [1] 6 - 24 == -18
#> Backtrace:
#> 1. global::expect_equal_applied(x, y, fns = list(sum, prod))
#> 2. purrr::map(fns, ~expect_equal(.x(object), .x(expected)))
#> 3. .f(.x[[i]], ...)
#> 4. testthat::expect_equal(.x(object), .x(expected))
由 reprex package (v2.0.1)
于 2021-09-17 创建关于为什么在{testthat}中似乎缺少这样的功能,我认为这不是真正必要的,我们可以用lapply
或map
构造它。