-
Notifications
You must be signed in to change notification settings - Fork 339
Description
Inspiration: r-lib/lintr#2927
I recently found a test that was silently passing with the format:
expect_true(all(x == y))
It should have failed because the "actual" value, x
, wound up being NULL
(think x <- df$COL
where a refactor removed the COL
vector from the data.frame).
With that in mind I think this style of test should be avoided at all costs (and there's nothing expect_true()
should do because it's all()
causing the issue).
That said, my immediate thought was to turn to expect_identical(x, y)
, with tolerance=
added as needed (or expect_equal
, pick your favorite).
But a very common style for this test is:
expect_true(all(x == "FOO"))
I.e., testing that a vector has a single value, "FOO"
.
I don't think there's a neat way to express that in {testthat} today. There are two stricter equivalents I've hit on, neither of which feel particularly satisfying:
# ugly, and all the uglier if 'x' is an expression!
expect_identical(x, rep("FOO", length(x))
# somewhat "tricky", and requires coercion for non-character 'x'
expect_named(table(x), "FOO")
## c.f.
expect_named(table(int_vector), "1")
## even worse
expect_named(table(dbl_vector), "3.14159265358979")
## still not fully satisfying
expect_identical(unique(x), "FOO")
expect_identical(unique(int_vector), 1L)
expect_identical(unique(dbl_vector), pi, tolerance=...)
Is this a good enough use case to generate its own expectation? Possibly #1836 could be related here -- if we remove the all()
call, {testthat} itself could catch the silent error case under the hood and offer a useful failure:
expect_true(x == "FOO", all = TRUE)
# internally, testthat finds 'x' to be empty and fails