A mocking library for R.
To install the latest CRAN release:
install.packages('mockery')
To install directly from the source code in this GitHub repository:
# If you don't have devtools installed yet:
install.packages('devtools')
# Then:
::install_github('r-lib/mockery') devtools
Mockery provides the capacity for stubbing out functions and for verifying function calls during testing.
Mockery’s stub
function will let you stub out a function
with another function or simply a return value. Note that if you choose
to replace the function with another function, the signatures of the two
functions should be compatible.
= function(y) y
g = function(x) g(x) + 1
f test_that('demonstrate stubbing', {
# replaces 'g' with a function that always returns 100
# but only when called from f
stub(f, 'g', 100)
# this can also be written
stub(f, 'g', function(...) 100)
expect_equal(f(1), 101)
})
Stubbing works with classes of all descriptions and namespaced functions:
# this stubs the 'request_perform' function, but only
# for httr::get, and only when it is called from within this
# test function
stub(httr::GET, 'request_perform', 'some html')
# it is also possible to stub out a namespaced function call
stub(some_function, 'namespace::function', 'some return value')
This also works with R6 classes and methods.
It’s possible to specify the depth of stubbing. This is useful if you want to stub a function that isn’t called directly by the function you call in your test, but is instead called by a function that that function calls.
In the example below, the function g
is both called
directly from r
, which we call from the test, and from
f
, which r
calls. By specifying a depth of 2,
we tell mockery to stub g
in both places.
= function(y) y
g = function(x) g(x) + 1
f = function(x) g(x) + f(x)
r test_that('demonstrate stubbing', {
stub(r, 'g', 100, depth=2)
expect_equal(r(1), 201)
})
For more examples, please see the test code contained in this repository.
Mockery’s stub
function has similar functionality to
testthat’s with_mock
.
There are several use cases in which mockery’s stub
function will work, but testthat’s with_mock
will not.
First, unlike with_mock
, it seamlessly allows for
mocking out primitives.
Second, it is easy to stub out functions from base R packages with
mockery’s stub
. Because of how with_mock
works, you can get into trouble if you mock such functions that the JIT
compiler might try to use. These kinds of problems are avoided by
stub
’s design. As of version 2.0.0 of testthat, it will be
impossible to mock functions from base R packages
with_mock
.
The functionality of stub
is just slightly different
than that of with_mock
. Instead of mocking out the object
of interest for the duration of some code block, it mocks it out only
when it is called from a specified function.
Mock objects allow you to specify the behavior of the function you’ve stubbed out while also verifying how that function was used.
= function(y) y
g = function(x) g(x) + 1
f test_that('demonstrate mock object usage', {
# mocks can specify behavior
= mock(100)
mock stub(f, 'g', mock)
= f(5)
result expect_equal(result, 101)
# and allow you to make assertions on the mock was treated
expect_called(mock, 1)
expect_args(mock, 1, 5)
})
You can also specify multiple return values
= mock(1, "a", sqrt(3)) mock
and access the arguments with which it was called.
<- mock()
mock mock(x = 1)
mock(y = 2)
expect_equal(length(mock), 2)
<- mock_args(mock)
args
expect_equal(args[[1]], list(x = 1))
expect_equal(args[[2]], list(y = 2))
Please report bugs and feature requests through github issues.