# mockery
<!-- badges: start -->
[![CRAN version](http://www.r-pkg.org/badges/version/mockery)](https://CRAN.r-project.org/package=mockery)
[![R-CMD-check](https://github.com/r-lib/mockery/actions/workflows/R-CMD-check.yaml/badge.svg)](https://github.com/r-lib/mockery/actions/workflows/R-CMD-check.yaml)
[![Codecov test coverage](https://codecov.io/gh/r-lib/mockery/branch/main/graph/badge.svg)](https://app.codecov.io/gh/r-lib/mockery?branch=main)
<!-- badges: end -->

A mocking library for R.

### Installation

To install the latest CRAN release:

```R
install.packages('mockery')
```

To install directly from the source code in this GitHub repository:

```R
# If you don't have devtools installed yet:
install.packages('devtools')

# Then:
devtools::install_github('r-lib/mockery')
```

### Testing

Mockery provides the capacity for stubbing out functions and for verifying
function calls during testing.

#### Stubbing

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.

##### Examples

```R
g = function(y) y
f = function(x) g(x) + 1
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:

```R
# 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.

###### Depth

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.

```R
g = function(y) y
f = function(x) g(x) + 1
r = function(x) g(x) + f(x)
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.

##### Comparison to with_mock

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.

#### Mocking

Mock objects allow you to specify the behavior of the function you've stubbed
out while also verifying how that function was used. 

```R
g = function(y) y
f = function(x) g(x) + 1
test_that('demonstrate mock object usage', {
    # mocks can specify behavior
    mock = mock(100)
    stub(f, 'g', mock)
    result = f(5)
    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

```R
mock = mock(1, "a", sqrt(3))
```

and access the arguments with which it was called.

```R
mock <- mock()
mock(x = 1)
mock(y = 2)

expect_equal(length(mock), 2)
args <- mock_args(mock)

expect_equal(args[[1]], list(x = 1))
expect_equal(args[[2]], list(y = 2))
```

---

Please report bugs and feature requests through github issues.
