Условия тестирования параметра функции с помощью testthat

У меня есть функция вида func(expr, data.sizes), где параметр expr является выражением, а параметр data.sizes обычно, как следует из названия, представляет собой вектор или последовательность размеров данных. (например: c(10, 100, 1000) или 10^seq(1, 3))

Я хотел бы написать несколько тестовых примеров для параметров моей функции, используя testthat, но я новичок в модульном тестировании в R, поэтому я хотел бы знать, как можно проверить условия для параметра (ов) функции, используя testthat?

Например, я хочу проверить возможное значение NA для параметра data.size в моей функции, и я написал этот фрагмент для проверки в своей консоли: (функция доступна в Global Env.)

test_that("NA test for data.sizes", {
  expect_false(is.na(data.sizes %in% func(expression, data.sizes = c(10, 100))))
})

который выдает ошибку:

* object 'data.sizes' not found
1: expect_false(is.na(data.sizes %in% func(expression, data.sizes = c(10, 
       10)))) at :2
2: quasi_label(enquo(object), label, arg = "object")
3: eval_bare(get_expr(quo), get_env(quo))
4: data.sizes %in% func(expression, data.sizes = c(10, 10))

Что я могу делать неправильно? Также каков синтаксис в целом для применения тестовых условий к параметрам функции с помощью testthat?


person Anirban166    schedule 07.06.2020    source источник


Ответы (2)


testthat проверяет, является ли результат функции тем, что вы ожидаете.

Если вы хотите проверить результат функции для NA, вы можете сделать для этого специальный тест:

library(testthat)
library(assertthat)

func <- function(expr,data.sizes) {
  assert_that(noNA(data.sizes))
  eval(expr)
}

test_that("data.sizes test for func", {
  # Success
  expect_error(func(expression(data.sizes[1]+data.sizes[2]), data.sizes = c(1,NA)))
  expect_equal(func(expression(data.sizes[1]+data.sizes[2]), data.sizes = c(1,2)),3)
  # Failure
  expect_equal(func(expression(data.sizes[1]+data.sizes[2]), data.sizes = c(1,2)),4)
})

Чтобы проверить правильность параметров внутри функции, вы можете использовать пакеты уверенного программирования, такие как assertthat.

person Waldi    schedule 07.06.2020

Ваш модульный тест может проверить вывод вашей функции с заданным вводом. Это не способ разрешить вашей функции проверять заданные переменные на наличие недопустимых входных данных. Это должно быть сделано внутри вашей функции.

Модульный тест должен просто вызвать вашу функцию с некоторыми параметрами и убедиться, что результат соответствует ожидаемому.

Предположим, например, что вы хотите, чтобы func возвращал список, содержащий повторения оцениваемого выражения в соответствии с data.sizes, например:

func <- function(expression, data.sizes)
{
  expression <- as.expression(as.list(match.call())$expression)
  if(!all(!is.na(data.sizes))) stop("data.sizes may not contain NAs")
  lapply(data.sizes, function(x) rep(eval(expression), x))
}

Чтобы он делал что-то вроде этого:

y <- 5
func(y^2 + 3, 1:3)
#> [[1]]
#> [1] 28
#> 
#> [[2]]
#> [1] 28 28
#> 
#> [[3]]
#> [1] 28 28 28

Но вы хотите, чтобы было выбрано исключение, если в data.sizes есть значения NA:

func(y^2 + 3, c(1, NA))
#> Error in func(y^2 + 3, c(1, NA)) : data.sizes may not contain NAs

Тогда ваш модульный тест будет выглядеть так:

test_that("NA test for data.sizes", {
  expect_list(func(y^2 + 3, 1:3))
  expect_error(func(y^2 + 3, c(1, NA)))
})

Таким образом, вы знаете, что если этот тест пройден, ваша ошибка будет устранена соответствующим образом.

person Allan Cameron    schedule 07.06.2020
comment
Это проясняет. Таким образом, мы предоставляем крайние случаи (например, проверки null/NA/NaN с соответствующими вызовами stop()) внутри нашей функции, а testthat проверяет только определенные случаи ввода при условии, что мы обрабатываем их в нашей функции упреждающе, а не для обобщенного тестового примера. сценарий. Спасибо и за подробный пример! Проголосовал, хотел бы я принять несколько ответов. - person Anirban166; 07.06.2020
comment
@ Anirban166 точно. Эти тесты становятся необходимыми, когда вы создаете новый пакет. Когда ваша кодовая база становится большой и содержит несколько функций, зависящих от других функций в вашем пакете, изменение одной функции может привести к неожиданным последствиям в другом месте. Автоматизированные тесты позволяют убедиться, что после внесения изменений все по-прежнему работает должным образом. - person Allan Cameron; 07.06.2020