{testthat} `quasi_label` с `expect_match` выдает «Ошибка: недопустимый тип аргумента»

#r #rlang #testthat #quasiquotes

#r #rlang #testthat #квазиквоты

Вопрос:

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

В качестве примера (повторите ниже) add_excitement добавляет восклицательный знак к своей входной строке. При вводе «привет» он должен возвращать «привет!»; при вводе любого другого ввода он не должен возвращать «привет!». Я хотел бы проверить поведение {testthat} на ряде шаблонов и возвращать информативные ошибки, которые указывают, какой шаблон вызвал ошибку.

Основываясь на документации по пакету {testthat}, я считаю, что я должен использовать expect_match . Однако это выдает ошибку «недопустимый тип аргумента», в то expect_identical время как работает. Я не понимаю, почему это происходит. Мои вопросы:

  • Почему expect_identical и не expect_match принимает quasi_label аргумент?
  • Могу ли я использовать expect_identical , а не expect_match для своих целей, или это может привести к другим ошибкам?

Вот повторный:

 library(testthat)
library(purrr)

patterns = c("hello", "goodbye", "cheers")
add_excitement <- function(pattern) paste0(pattern, "!")

# For a single pattern
show_failure(expect_identical(add_excitement(!!patterns[2]), "hello!"))
#> Failed expectation:
#> add_excitement("goodbye") not identical to "hello!".
#> 1/1 mismatches
#> x[1]: "goodbye!"
#> y[1]: "hello!"
try(
  show_failure(expect_match(add_excitement(!!patterns[2]), "hello!", fixed = TRUE,all = TRUE))
)
#> Error in !patterns[2] : invalid argument type

# For multiple patterns
purrr::map(
  patterns, 
  ~ show_failure(expect_identical(add_excitement(!!.), "hello!"))
)
#> Failed expectation:
#> add_excitement("goodbye") not identical to "hello!".
#> 1/1 mismatches
#> x[1]: "goodbye!"
#> y[1]: "hello!"
#> Failed expectation:
#> add_excitement("cheers") not identical to "hello!".
#> 1/1 mismatches
#> x[1]: "cheers!"
#> y[1]: "hello!"
#> [[1]]
#> NULL
#> 
#> [[2]]
#> NULL
#> 
#> [[3]]
#> NULL

try(
  purrr::map(
    patterns, 
    ~ show_failure(expect_match(add_excitement(!!.), "hello!", 
                                fixed = TRUE, all = TRUE)
    )
  )
)
#> Error in !. : invalid argument type
 

Создано 2021-02-04 пакетом reprex (версия 0.3.0)

Спасибо за вашу помощь!

Ответ №1:

Я смог решить эту проблему следующим образом https://r-pkgs.org/tests.html#building-your-own-testing-tools , который использует нестандартную оценку bquote() и eval() (вместо quasi_label() ) для получения более информативных ошибок.

 library(testthat)
library(purrr)

patterns = c("hello", "goodbye", "cheers")
add_excitement <- function(pattern) paste0(pattern, "!")

show_failure(eval(bquote(expect_match(add_excitement(.(patterns[2])), "hello!", fixed = TRUE, all = TRUE))))
#> Failed expectation:
#> add_excitement("goodbye") does not match "hello!".
#> Actual value: "goodbye!"


purrr::walk(
  patterns,
  ~ show_failure(eval(bquote(expect_match(add_excitement(.(.)), "hello!", fixed = TRUE, all = TRUE))))
)
#> Failed expectation:
#> add_excitement("goodbye") does not match "hello!".
#> Actual value: "goodbye!"
#> Failed expectation:
#> add_excitement("cheers") does not match "hello!".
#> Actual value: "cheers!"
 

Создано 2021-02-04 пакетом reprex (версия 0.3.0)

Или для аккуратной версии:

 library(testthat)
library(purrr)

patterns = c("hello", "goodbye", "cheers")
add_excitement <- function(pattern) paste0(pattern, "!")

expect_hello <- function(pattern) {
  show_failure(eval(bquote(expect_match(add_excitement(.(pattern)), "hello!", fixed = TRUE, all = TRUE))))
}

expect_hello(patterns[2])
#> Failed expectation:
#> add_excitement("goodbye") does not match "hello!".
#> Actual value: "goodbye!"

walk(patterns, expect_hello)
#> Failed expectation:
#> add_excitement("goodbye") does not match "hello!".
#> Actual value: "goodbye!"
#> Failed expectation:
#> add_excitement("cheers") does not match "hello!".
#> Actual value: "cheers!"
 

Создано 2021-02-04 пакетом reprex (версия 0.3.0)

Ответ №2:

Ошибка связана с использованием оператора tidyeval bang bang !! .
Это заменяется, и приведенный вами пример работает без :

 show_failure(expect_identical(add_excitement(patterns[2]), "hello!"))

# Failed expectation:
# add_excitement(patterns[2]) not identical to "hello!".
# 1/1 mismatches
# x[1]: "goodbye!"
# y[1]: "hello!"

show_failure(expect_match(add_excitement(patterns[2]), "hello!", fixed = TRUE,all = TRUE))

# Failed expectation:
# add_excitement(patterns[2]) does not match "hello!".
# Actual value: "goodbye!"

purrr::map(
  patterns, 
  ~ show_failure(expect_match(add_excitement(.x), "hello!", 
                              fixed = TRUE, all = TRUE)
  )
)

Failed expectation:
add_excitement(.x) does not match "hello!".
Actual value: "goodbye!"
Failed expectation:
add_excitement(.x) does not match "hello!".
Actual value: "cheers!"
[[1]]
NULL

[[2]]
NULL

[[3]]
NULL
 

Комментарии:

1. Спасибо. Однако версия без tidyeval не показывает pattern ошибку в ошибке. show_failure(expect_identical(add_excitement(!!patterns[2]), "hello!")) дает add_excitement("goodbye") not identical to "hello!". , но show_failure(expect_identical(add_excitement(patterns[2]), "hello!")) дает менее информативный add_excitement(patterns[2]) not identical to "hello!".

2. Спасибо за ваш отзыв и рад, что вы нашли решение!