Nothing
#' Mock functions in a package
#'
#' `local_mock()` temporarily substitutes implementations of package functions.
#' This is useful for testing code that relies on functions that are
#' slow, have unintended side effects or access resources that may not be
#' available when testing.
#'
#' This works by adding a shadow environment as a parent of the environment
#' in which the expressions are evaluated. Everything happens at the R level,
#' but only functions in your own package can be mocked.
#' Otherwise, the implementation is modeled after the original version in the
#' `testthat` package, which is now deprecated.
#'
#' @param ... `[any]`\cr Named arguments redefine mocked functions.
#' An unnamed argument containing code in braces (`{}`) should be provided
#' to `with_mock()`,
#' it will be evaluated after mocking the functions.
#' Use `:=` to mock functions that start with a dot
#' to avoid potential collision with current or future arguments
#' to `with_mock()` or `local_mock()`.
#' Passing more than one unnamed argument to `with_mock()`,
#' or code that is not inside braces, gives a warning.
#' @param .parent `[environment]`\cr the environment in which to evaluate the expressions,
#' defaults to [parent.frame()]. Usually doesn't need to be changed.
#' @param .env `[environment]`\cr the environment in which to patch the functions,
#' defaults to [topenv()]. Usually doesn't need to be changed.
#' @param .defer_env `[environment]`\cr
#' Attach exit handlers to this environment.
#' Typically, this should be either the current environment
#' or a parent frame (accessed through [parent.frame()]).
#' This argument is passed on as `envir` to [withr::defer()].
#' @return
#' `local_mock()` returns `NULL`, invisibly.
#' @references Suraj Gupta (2012): [How R Searches And Finds Stuff](https://blog.thatbuthow.com/how-r-searches-and-finds-stuff/)
#' @export
#' @examples
#' some_func <- function() stop("oops")
#' some_other_func <- function() some_func()
#' my_env <- environment()
#'
#' tester_func <- function() {
#' # The default for .env works well most of the time,
#' # unfortunately not in examples
#' local_mock(some_func = function() 42, .env = my_env)
#' some_other_func()
#' }
#' try(some_other_func())
#' tester_func()
local_mock <- function(...,
.parent = parent.frame(),
.env = get_mock_env(.parent),
.defer_env = parent.frame()) {
dots <- enquos(...)
check_dots_env(dots, .parent)
if (length(get_code_dots(dots, warn = FALSE)) > 0) {
abort("All arguments to `local_mock()` must be named.")
}
mock_funs <- get_mock_dots(dots)
if (length(mock_funs) == 0) {
return()
}
mock_env <- create_mock_env(
mock_funs, .env = .env, .parent = .parent, .defer_env = .defer_env
)
local_mock_env(mock_env, .parent, .defer_env)
invisible()
}
#' @description
#' `with_mock()` substitutes, runs code locally, and restores in one go.
#' @return
#' `with_mock()` returns the result of the last unnamed argument.
#' Visibility is preserved.
#' @rdname local_mock
#' @export
#' @examples
#'
#' tester_func_with <- function() {
#' with_mock(
#' some_func = function() 42,
#' .env = my_env,
#' {
#' some_other_func()
#' }
#' )
#' }
#' tester_func_with()
with_mock <- function(...,
.parent = parent.frame(),
.env = get_mock_env(.parent)) {
dots <- enquos(...)
check_dots_env(dots, .parent)
mock_funs <- get_mock_dots(dots)
mock_env <- create_mock_env(mock_funs, .env = .env, .parent = .parent)
local_mock_env(mock_env, .parent)
evaluate_code(get_code_dots(dots), .parent)
}
get_mock_dots <- function(dots) {
mock_qual_names <- names2(dots)
if (all(mock_qual_names == "")) {
warn("Not mocking anything. Please use named arguments to specify the functions you want to mock.")
list()
} else {
dots[mock_qual_names != ""]
}
}
get_code_dots <- function(dots, warn = TRUE) {
mock_qual_names <- names2(dots)
if (all(mock_qual_names != "")) {
if (warn) {
warn("Not evaluating anything. Please use unnamed arguments to specify expressions you want to evaluate.")
}
list()
} else {
dots[mock_qual_names == ""]
}
}
Any scripts or data that you put into this service are public.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.