1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117
|
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/mock2.R
\name{local_mocked_bindings}
\alias{local_mocked_bindings}
\alias{with_mocked_bindings}
\title{Mocking tools}
\usage{
local_mocked_bindings(..., .package = NULL, .env = caller_env())
with_mocked_bindings(code, ..., .package = NULL)
}
\arguments{
\item{...}{Name-value pairs providing new values (typically functions) to
temporarily replace the named bindings.}
\item{.package}{The name of the package where mocked functions should be
inserted. Generally, you should not supply this as it will be automatically
detected when whole package tests are run or when there's one package
under active development (i.e. loaded with \code{\link[pkgload:load_all]{pkgload::load_all()}}).
We don't recommend using this to mock functions in other packages,
as you should not modify namespaces that you don't own.}
\item{.env}{Environment that defines effect scope. For expert use only.}
\item{code}{Code to execute with specified bindings.}
}
\description{
\code{with_mocked_bindings()} and \code{local_mocked_bindings()} provide tools for
"mocking", temporarily redefining a function so that it behaves differently
during tests. This is helpful for testing functions that depend on external
state (i.e. reading a value from a file or a website, or pretending a package
is or isn't installed).
These functions represent a second attempt at bringing mocking to testthat,
incorporating what we've learned from the mockr, mockery, and mockthat
packages.
}
\section{Use}{
There are four places that the function you are trying to mock might
come from:
\itemize{
\item Internal to your package.
\item Imported from an external package via the \code{NAMESPACE}.
\item The base environment.
\item Called from an external package with \code{::}.
}
They are described in turn below.
\subsection{Internal & imported functions}{
You mock internal and imported functions the same way. For example, take
this code:
\if{html}{\out{<div class="sourceCode R">}}\preformatted{some_function <- function() \{
another_function()
\}
}\if{html}{\out{</div>}}
It doesn't matter whether \code{another_function()} is defined by your package
or you've imported it from a dependency with \verb{@import} or \verb{@importFrom},
you mock it the same way:
\if{html}{\out{<div class="sourceCode R">}}\preformatted{local_mocked_bindings(
another_function = function(...) "new_value"
)
}\if{html}{\out{</div>}}
}
\subsection{Base functions}{
To mock a function in the base package, you need to make sure that you
have a binding for this function in your package. It's easiest to do this
by binding the value to \code{NULL}. For example, if you wanted to mock
\code{interactive()} in your package, you'd need to include this code somewhere
in your package:
\if{html}{\out{<div class="sourceCode R">}}\preformatted{interactive <- NULL
}\if{html}{\out{</div>}}
Why is this necessary? \code{with_mocked_bindings()} and \code{local_mocked_bindings()}
work by temporarily modifying the bindings within your package's namespace.
When these tests are running inside of \verb{R CMD check} the namespace is locked
which means it's not possible to create new bindings so you need to make sure
that the binding exists already.
}
\subsection{Namespaced calls}{
It's trickier to mock functions in other packages that you call with \code{::}.
For example, take this minor variation:
\if{html}{\out{<div class="sourceCode R">}}\preformatted{some_function <- function() \{
anotherpackage::another_function()
\}
}\if{html}{\out{</div>}}
To mock this function, you'd need to modify \code{another_function()} inside the
\code{anotherpackage} package. You \emph{can} do this by supplying the \code{.package}
argument to \code{local_mocked_bindings()} but we don't recommend it because
it will affect all calls to \code{anotherpackage::another_function()}, not just
the calls originating in your package. Instead, it's safer to either import
the function into your package, or make a wrapper that you can mock:
\if{html}{\out{<div class="sourceCode R">}}\preformatted{some_function <- function() \{
my_wrapper()
\}
my_wrapper <- function(...) \{
anotherpackage::another_function(...)
\}
local_mocked_bindings(
my_wrapper = function(...) "new_value"
)
}\if{html}{\out{</div>}}
}
}
|