gxs_function {xpectr}R Documentation

Generate testhat expectations for argument values in a function

Description

[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.

Usage

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
)

Arguments

fn

Function to create tests for.

args_values

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.

extra_combinations

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.

check_nulls

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

Indentation of the selection. (Numeric)

tolerance

The tolerance for numeric tests as a string, like "1e-4". (Character)

round_to_tolerance

Whether to round numeric elements to the specified tolerance. (Logical)

This is currently applied to numeric columns and vectors (excluding some lists).

strip

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.

sample_n

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.

envir

Environment to evaluate in. Defaults to parent.frame().

copy_env

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.

assign_output

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

seed to set. (Whole number)

add_wrapper_comments

Whether to add intro and outro comments. (Logical)

add_test_comments

Whether to add comments for each test. (Logical)

start_with_newline, end_with_newline

Whether to have a newline in the beginning/end. (Logical)

out

Either "insert" or "return".

"insert" (Default)

Inserts the expectations via rstudioapi::insertText().

"return"

Returns the expectations in a list.

These can be prepared for insertion with prepare_insertion().

parallel

Whether to parallelize the generation of expectations. (Logical)

Requires a registered parallel backend. Like with doParallel::registerDoParallel.

Details

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!

Value

Either NULL or the unprepared expectations as a character vector.

Author(s)

Ludvig Renbo Olsen, r-pkgs@ludvigolsen.dk

See Also

Other expectation generators: gxs_selection(), initializeGXSFunctionAddin(), insertExpectationsAddin()

Examples

# Attach packages
library(xpectr)

## Not run: 
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))
             )

## End(Not run)

[Package xpectr version 0.4.3 Index]