{testthat} `quasi_label` with `expect_match` throws "Error: invalid argument type"

112 views Asked by At

I am new to {testthat} and am building tests for a function that modifies strings and is expected to produce a specific output for certain input patterns.

As a example (reprex below), add_excitement adds an exclamation point to its input string. When given an input of "hello" it should return "hello!"; when given any other input it should not return "hello!". I would like to {testthat} behavior on a series of patterns and return informative errors which specify which pattern caused the error.

Based on {testthat} package documentation, I believe I should use expect_match. However, this throws an "invalid argument type" error, whereas expect_identical works. I don't understand why this is happening. My questions are:

  • Why does expect_identical and not expect_match accept the quasi_label argument?
  • Could I use expect_identical rather than expect_match for my purposes, or does this risk other errors?

Here is a reprex:

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

Created on 2021-02-04 by the reprex package (v0.3.0)

Thank you for your help!

2

There are 2 answers

2
Waldi On

The error is linked to the use of tidyeval bang bang !! operator.
This is superseded, and the example you provided works without :

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
0
maia-sh On

I was able to solve this problem following https://r-pkgs.org/tests.html#building-your-own-testing-tools, which uses non-standard evaluation bquote() and eval() (instead of quasi_label()) to produce the more informative errors.

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!"

Created on 2021-02-04 by the reprex package (v0.3.0)

Or for a tidy version:

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!"

Created on 2021-02-04 by the reprex package (v0.3.0)