
Last chance! 50% off unlimited learning
Sale ends in
Last chance! 50% off unlimited learning
Sale ends in
lifecycle::badge("experimental")
Based on a set of supplied values for each function argument,
a set of testthat
expect_*
statements are generated.
Included tests: The first value supplied for an argument is considered the valid baseline value. For each argument, we create tests for each of the supplied values, where the other arguments have their baseline value.
When testing a function that alters non-local variables, consider enabling `copy_env`
.
See supported objects in details
.
gxs_function(
fn,
args_values,
extra_combinations = NULL,
check_nulls = TRUE,
indentation = 0,
tolerance = "1e-4",
round_to_tolerance = TRUE,
strip = TRUE,
sample_n = 30,
envir = NULL,
copy_env = FALSE,
assign_output = TRUE,
seed = 42,
add_wrapper_comments = TRUE,
add_test_comments = TRUE,
start_with_newline = TRUE,
end_with_newline = TRUE,
out = "insert",
parallel = FALSE
)
Either NULL
or the unprepared expectations as a character vector
.
Function to create tests for.
The arguments and the values to create tests for. Should be supplied as a named list of lists, like the following:
args_values = list(
"x1" = list(1, 2, 3),
"x2" = list("a", "b", "c")
)
The first value for each argument (referred to as the 'baseline' value) should be valid
(not throw an error/
message
/warning
).
N.B. This is not checked but should lead to more meaningful tests.
N.B. Please define the list directly in the function call. This is currently necessary.
Additional combinations to test. List of lists, where each combination is a named sublist.
E.g. the following two combinations:
extra_combinations = list(
list("x1" = 4, "x2" = "b"),
list("x1" = 7, "x2" = "c")
)
N.B. Unspecified arguments gets the baseline value.
If you find yourself adding many combinations,
an additional gxs_function()
call with different baseline values
might be preferable.
Whether to try all arguments with NULL
. (Logical)
When enabled, you don't need to add NULL
to your `args_values`
,
unless it should be the baseline value.
Indentation of the selection. (Numeric)
The tolerance for numeric tests as a string, like "1e-4"
. (Character)
Whether to round numeric elements to the specified tolerance. (Logical)
This is currently applied to numeric columns and vectors (excluding some lists).
Whether to insert
strip_msg()
and
strip()
in tests of side effects. (Logical)
Sometimes testthat tests have differences in punctuation and newlines on different systems. By stripping both the error message and the expected message of non-alphanumeric symbols, we can avoid such failed tests.
The number of elements/rows to sample. Set to NULL
to avoid sampling.
Inserts smpl()
in the generated tests when sampling was used. A seed is
set internally, setting sample.kind
as "Rounding"
to ensure compatibility with R
versions
< 3.6.0
.
The order of the elements/rows is kept intact. No replacement is used, why no oversampling will take place.
When testing a big data.frame
, sampling the rows can help keep the test files somewhat readable.
Environment to evaluate in. Defaults to
parent.frame()
.
Whether each combination should be tested in a deep copy of the environment. (Logical)
Side effects will be captured in copies of the copy, why two copies of the environment will exist at the same time.
Disabled by default to save memory but is often preferable to enable, e.g. when the function changes non-local variables.
Whether to assign the output of a function call or long selection to a variable. This will avoid recalling the function and decrease cluttering. (Logical)
Heuristic: when the `selection`
isn't of a string and contains a parenthesis, it is considered a function call.
A selection with more than 30 characters will be assigned as well.
The tests themselves can be more difficult to interpret, as you will have to look at the assignment to see the object that is being tested.
seed
to set. (Whole number)
Whether to add intro and outro comments. (Logical)
Whether to add comments for each test. (Logical)
Whether to have a newline in the beginning/end. (Logical)
Either "insert"
or "return"
.
Inserts the expectations via
rstudioapi::insertText()
.
Returns the expectations in a list
.
These can be prepared for insertion with
prepare_insertion()
.
Whether to parallelize the generation of expectations. (Logical)
Requires a registered parallel backend. Like with doParallel::registerDoParallel
.
Ludvig Renbo Olsen, r-pkgs@ludvigolsen.dk
The following "types" are currently supported or intended to be supported in the future. Please suggest more types and tests in a GitHub issue!
Note: A set of fallback tests will be generated for unsupported objects.
Type | Supported | Notes |
Side effects | Yes | Errors, warnings, and messages. |
Vector | Yes | Lists are treated differently, depending on their structure. |
Factor | Yes | |
Data Frame | Yes | List columns (like nested tibbles) are currently skipped. |
Matrix | Yes | Supported but could be improved. |
Formula | Yes | |
Function | Yes | |
NULL | Yes | |
Array | No | |
Dates | No | Base and lubridate . |
ggplot2 | No | This may be a challenge, but would be cool! |
Other expectation generators:
gxs_selection()
,
initializeGXSFunctionAddin()
,
insertExpectationsAddin()
# Attach packages
library(xpectr)
if (FALSE) {
fn <- function(x, y, z){
if (x>3) stop("'x' > 3")
if (y<0) warning("'y'<0")
if (z==10) message("'z' was 10!")
x + y + z
}
# Create expectations
# Note: define the list in the call
gxs_function(fn,
args_values = list(
"x" = list(2, 4, NA),
"y" = list(0, -1),
"z" = list(5, 10))
)
# Add additional combinations
gxs_function(fn,
args_values = list(
"x" = list(2, 4, NA),
"y" = list(0, -1),
"z" = list(5, 10)),
extra_combinations = list(
list("x" = 4, "z" = 10),
list("y" = 1, "z" = 10))
)
}
Run the code above in your browser using DataLab