[med-svn] [r-cran-mockery] 01/02: New upstream version 0.4.1

Andreas Tille tille at debian.org
Fri Nov 24 16:50:12 UTC 2017


This is an automated email from the git hooks/post-receive script.

tille pushed a commit to branch master
in repository r-cran-mockery.

commit 49f56e214313a64fdb4a1b5c5cd365f9a46f0d07
Author: Andreas Tille <tille at debian.org>
Date:   Fri Nov 24 17:43:43 2017 +0100

    New upstream version 0.4.1
---
 DESCRIPTION                       |  31 +++
 LICENSE                           |   2 +
 MD5                               |  21 ++
 NAMESPACE                         |  13 ++
 NEWS                              |  12 ++
 R/expectations.R                  | 130 ++++++++++++
 R/mock-object.R                   | 146 +++++++++++++
 R/mockery.R                       |  34 +++
 R/stub.R                          | 169 +++++++++++++++
 README.md                         | 153 ++++++++++++++
 build/vignette.rds                | Bin 0 -> 226 bytes
 inst/doc/mocks-and-testthat.R     | 126 +++++++++++
 inst/doc/mocks-and-testthat.Rmd   | 252 ++++++++++++++++++++++
 inst/doc/mocks-and-testthat.html  | 434 ++++++++++++++++++++++++++++++++++++++
 man/call-expectations.Rd          |  55 +++++
 man/mock.Rd                       | 106 ++++++++++
 man/mockery.Rd                    |  37 ++++
 man/stub.Rd                       |  45 ++++
 tests/testthat.R                  |   4 +
 tests/testthat/test-mock-object.R | 179 ++++++++++++++++
 tests/testthat/test_stub.R        | 332 +++++++++++++++++++++++++++++
 vignettes/mocks-and-testthat.Rmd  | 252 ++++++++++++++++++++++
 22 files changed, 2533 insertions(+)

diff --git a/DESCRIPTION b/DESCRIPTION
new file mode 100644
index 0000000..8cb4324
--- /dev/null
+++ b/DESCRIPTION
@@ -0,0 +1,31 @@
+Package: mockery
+Version: 0.4.1
+Title: Mocking Library for R
+Description: 
+    The two main functionalities of this package are creating mock
+    objects (functions) and selectively intercepting calls to a given
+    function that originate in some other function. It can be used
+    with any testing framework available for R. Mock objects can
+    be injected with either this package's own stub() function or a
+    similar with_mock() facility present in the testthat package. 
+Authors at R: c(
+    person("Noam", "Finkelstein", role = c("aut", "cre"),
+           email = "noam.finkelstein at jhu.edu"),
+    person("Lukasz", "Bartnik", rol = c("aut"),
+           email = "l.bartnik at gmail.com")
+    )
+URL: https://github.com/n-s-f/mockery
+BugReports: https://github.com/n-s-f/mockery/issues
+Imports: testthat
+Suggests: knitr, rmarkdown (>= 1.0)
+License: MIT + file LICENSE
+Collate: 'expectations.R' 'mockery.R' 'mock-object.R' 'stub.R'
+VignetteBuilder: knitr
+RoxygenNote: 6.0.1
+NeedsCompilation: no
+Packaged: 2017-11-10 14:58:33 UTC; noam
+Author: Noam Finkelstein [aut, cre],
+  Lukasz Bartnik [aut]
+Maintainer: Noam Finkelstein <noam.finkelstein at jhu.edu>
+Repository: CRAN
+Date/Publication: 2017-11-10 18:22:21 UTC
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..1762254
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,2 @@
+YEAR: 2016
+COPYRIGHT HOLDER: Noam Finkelstein, Lukasz Bartnik
diff --git a/MD5 b/MD5
new file mode 100644
index 0000000..f234b7c
--- /dev/null
+++ b/MD5
@@ -0,0 +1,21 @@
+e732efce7de7dbcc8724f7f2dbcfb1a8 *DESCRIPTION
+3d598f5220436233590531b1de2f14b4 *LICENSE
+7d0483b34bc263b9accf579e55eafe60 *NAMESPACE
+ab111abd065205444612fd3a6316fb53 *NEWS
+29fab533619bbf0b79f008f4c5d81d3f *R/expectations.R
+6bd1b03af221e687d19b6d9abec4aa01 *R/mock-object.R
+0cfe2a6243fd4bb782f5243bef1681dd *R/mockery.R
+966b285097e526a71e5ab3300c416ba5 *R/stub.R
+69537e7efbb09e3ad6d0e9c0d3da57c6 *README.md
+dc43b969e6b3e7baeb161990a9a9a773 *build/vignette.rds
+03f278824fd4bba9adcb6aa16815e422 *inst/doc/mocks-and-testthat.R
+710dff0033da00ba9514450a0c4f7445 *inst/doc/mocks-and-testthat.Rmd
+30cdc4c20e7e53d9312b1611486c21b8 *inst/doc/mocks-and-testthat.html
+2a44bbe6cf2f5f7f420d88ecc506ce86 *man/call-expectations.Rd
+e8ebb1f75ae4033bec35f85dff80a1e1 *man/mock.Rd
+307d59ba3a7efe7341616c00548a93ab *man/mockery.Rd
+94bfd4dda4facc03b153da7b97336323 *man/stub.Rd
+aa03655779278d76db7f4ee3d7e1712c *tests/testthat.R
+146022703ddd614dc91c4054075d7947 *tests/testthat/test-mock-object.R
+ca068140f0dae8f7b08366b5796b9c3f *tests/testthat/test_stub.R
+710dff0033da00ba9514450a0c4f7445 *vignettes/mocks-and-testthat.Rmd
diff --git a/NAMESPACE b/NAMESPACE
new file mode 100644
index 0000000..273db99
--- /dev/null
+++ b/NAMESPACE
@@ -0,0 +1,13 @@
+# Generated by roxygen2: do not edit by hand
+
+S3method(length,mock)
+export(expect_args)
+export(expect_call)
+export(expect_called)
+export(mock)
+export(mock_args)
+export(mock_calls)
+export(stub)
+importFrom(testthat,expect)
+importFrom(testthat,expect_equal)
+importFrom(testthat,fail)
diff --git a/NEWS b/NEWS
new file mode 100644
index 0000000..223c4ba
--- /dev/null
+++ b/NEWS
@@ -0,0 +1,12 @@
+v 0.4.1
+
+Fix bug whereby functions that begin with `.` don't have things mocked out in
+them.
+
+v 0.4.0
+
+Add support for stubbing depth greater than 1.
+
+Add support for nested R6 classes.
+
+
diff --git a/R/expectations.R b/R/expectations.R
new file mode 100644
index 0000000..ae0ef08
--- /dev/null
+++ b/R/expectations.R
@@ -0,0 +1,130 @@
+
+#' Expectation: does the given call match the expected?
+#'
+#' Together with \code{\link{mock}} can be used to verify whether the
+#' call expression (\code{\link{expect_call}}) and/or argument values
+#' (\code{\link{expect_args}}) match the expected.
+#'
+#' With \code{expect_called} you can check how many times has the mock
+#' object been called.
+#'
+#' @param mock_object A \code{\link{mock}} object.
+#' @param n Call number or total number of calls.
+#' @param expected_call Expected call expression; will be compared unevaluated.
+#' @param ... Arguments as passed in a call.
+#'
+#' @examples
+#' library(testthat)
+#'
+#' # expect call expression (signature)
+#' m <- mock()
+#' with_mock(summary = m, summary(iris))
+#'
+#' # it has been called once
+#' expect_called(m, 1)
+#'
+#' # the first (and only) call's arguments matches summary(iris)
+#' expect_call(m, 1, summary(iris))
+#'
+#' # expect argument value
+#' m <- mock()
+#' a <- iris
+#' with_mock(summary = m, summary(object = a))
+#' expect_args(m, 1, object = a)
+#' # is an equivalent to ...
+#' expect_equal(mock_args(m)[[1]], list(object = a))
+#'
+#' @name call-expectations
+#'
+NULL
+
+
+
+#' @export
+#' @rdname call-expectations
+#'
+#' @importFrom testthat expect
+expect_call <- function (mock_object, n, expected_call) {
+  stopifnot(is_mock(mock_object))
+
+  expect(
+    0 < n && n <= length(mock_object),
+    sprintf("call number %s not found in mock object", toString(n))
+  )
+
+  expected_call <- substitute(expected_call)
+  mocked_call <- mock_calls(mock_object)[[n]]
+
+  format_call <- function (x) paste(trimws(deparse(x)), collapse = ' ')
+  
+  expect(
+    identical(mocked_call, expected_call),
+    sprintf("expected call %s does not mach actual call %s.",
+            format_call(expected_call), format_call(mocked_call))
+  )
+
+  invisible(TRUE)
+}
+
+
+#' @export
+#' @rdname call-expectations
+#'
+#' @importFrom testthat expect expect_equal
+expect_args <- function (mock_object, n, ...)
+{
+  stopifnot(is_mock(mock_object))
+
+  expect(
+    0 < n && n <= length(mock_object),
+    sprintf("arguments list number %s not found in mock object", toString(n))
+  )
+
+  expected_args <- list(...)
+  actual_args   <- mock_args(mock_object)[[n]]
+  
+  expect_equal(length(actual_args), length(expected_args),
+               info = 'number of expected args does not match the actual')
+  
+  for (i in seq_along(actual_args)) {
+    expect_equal(
+      actual_args[[i]],
+      expected_args[[i]],
+      label = paste(ordinal(i), 'actual argument'),
+      expected.label = paste(ordinal(i), 'expected argument')
+    ) 
+  }
+
+  invisible(TRUE)
+}
+
+
+ordinal <- function (x) 
+{
+  stopifnot(is.integer(x), x > 0, length(x) == 1)
+  if (x %in% 11:13)
+    return(paste0(x, 'th'))
+
+  as_string  <- as.character(x)
+  last_digit <- substring(as_string, nchar(as_string))
+  suffix <- switch(last_digit,
+         `1` = 'st',
+         `2` = 'nd',
+         `3` = 'rd',
+               'th')
+  paste0(as_string, suffix)
+}
+
+
+#' @export
+#' @rdname call-expectations
+expect_called <- function (mock_object, n)
+{
+  stopifnot(is_mock(mock_object))
+
+  expect(
+    length(mock_object) == n,
+    sprintf("mock object has not been called %s time%s", toString(n),
+            (if(n>1) "s" else ""))
+  )
+}
diff --git a/R/mock-object.R b/R/mock-object.R
new file mode 100644
index 0000000..ffe6e09
--- /dev/null
+++ b/R/mock-object.R
@@ -0,0 +1,146 @@
+
+#' Create and query a mocked function.
+#'
+#' Mock object's primary use is to record calls that are made on the
+#' mocked function.
+#'
+#' Optionally values/expressions can be passed via \code{...} for the
+#' mock object to return them upon subsequent calls. Expressions are
+#' evaluated in environment \code{envir} before being returned. If no
+#' value is passed in \code{...} then \code{NULL} is returned.
+#'
+#' Passing an expression or a function call via \code{...} is also a
+#' way to implement side effects: keep track of the state of code
+#' under testing, throw an exception when a condition is met, etc.
+#'
+#' \code{mock_calls} and \code{mock_args} can be used to access the
+#' list of calls made on a mocked function and a respective list of
+#' values of arguments passed to each of these calls.
+#'
+#'
+#' @param ... Values returned upon subsequent calls.
+#' @param cycle Whether to cycle over the return values. If \code{FALSE},
+#'        will fail if called too many times.
+#' @param envir Where to evaluate the expressions being returned.
+#' @param m A \code{\link{mock}}ed function.
+#' @param x A \code{\link{mock}}ed function.
+#'
+#' @return \code{mock()} returns a mocked function which can be then used
+#'         with \code{\link{with_mock}}.
+#' @return \code{mock_args()} returns a \code{list} of \code{list}s
+#'         of argument values.
+#' @return \code{mock_calls()} returns a \code{list} of \code{call}s.
+#' @return \code{length.mock()} returns the number of calls invoked on \code{m}.
+#'
+#' @examples
+#' library(testthat)
+#'
+#' m <- mock(1)
+#' with_mock(summary = m, {
+#'   expect_equal(summary(iris), 1)
+#'   expect_called(m, 1)
+#'   expect_call(m, 1, summary(iris))
+#'   expect_args(m, 1, iris)
+#' })
+#'
+#' # multiple return values
+#' m <- mock(1, "a", sqrt(3))
+#' with_mock(summary = m, {
+#'   expect_equal(summary(iris), 1)
+#'   expect_equal(summary(iris), "a")
+#'   expect_equal(summary(iris), 1.73, tolerance = .01)
+#' })
+#'
+#' # side effects
+#' m <- mock(1, 2, stop("error"))
+#' with_mock(summary = m, {
+#'   expect_equal(summary(iris), 1)
+#'   expect_equal(summary(iris), 2)
+#'   expect_error(summary(iris), "error")
+#' })
+#'
+#' # accessing call expressions
+#' m <- mock()
+#' m(x = 1)
+#' m(y = 2)
+#' expect_equal(length(m), 2)
+#' calls <- mock_calls(m)
+#' expect_equal(calls[[1]], quote(m(x = 1)))
+#' expect_equal(calls[[2]], quote(m(y = 2)))
+#'
+#' # accessing values of arguments
+#' m <- mock()
+#' m(x = 1)
+#' m(y = 2)
+#' expect_equal(length(m), 2)
+#' args <- mock_args(m)
+#' expect_equal(args[[1]], list(x = 1))
+#' expect_equal(args[[2]], list(y = 2))
+#'
+#'
+#' @name mock
+NULL
+
+
+#' @export
+#' @rdname mock
+#'
+#' @importFrom testthat fail
+mock <- function (..., cycle = FALSE, envir = parent.frame()) {
+  stopifnot(is.environment(envir))
+
+  return_values     <- eval(substitute(alist(...)))
+  return_values_env <- envir
+  call_no           <- 0
+  calls             <- list()
+  args              <- list()
+
+  mock_impl <- function(...) {
+    call_no <<- call_no + 1
+    calls[[call_no]] <<- match.call()
+
+    args[[call_no]] <<- list(...)
+
+    if (length(return_values)) {
+      if (call_no > length(return_values) && !cycle)
+        fail("too many calls to mock object and cycle set to FALSE")
+
+      value <- return_values[[(call_no - 1) %% length(return_values) + 1]]
+      return(eval(value, envir = return_values_env))
+    }
+
+    # TODO maybe it should the mock object itself?
+    invisible(NULL)
+  }
+
+  class(mock_impl) <- 'mock'
+  mock_impl
+}
+
+
+#' @export
+#' @rdname mock
+mock_args <- function (m) {
+  stopifnot(is_mock(m))
+  environment(m)$args
+}
+
+
+#' @export
+#' @rdname mock
+mock_calls <- function (m) {
+  stopifnot(is_mock(m))
+  environment(m)$calls
+}
+
+
+is_mock <- function (object) inherits(object, 'mock')
+
+
+#' @export
+#' @rdname mock
+length.mock <- function (x)
+{
+  length(environment(x)$calls)
+}
+
diff --git a/R/mockery.R b/R/mockery.R
new file mode 100644
index 0000000..e19f5e3
--- /dev/null
+++ b/R/mockery.R
@@ -0,0 +1,34 @@
+#' R package to make mocking easier
+#'
+#' There are great tools for unit testing in R out there already but
+#' they don't come with a lot of support for mock objects. This
+#' package aims at fixing that.
+#'
+#' @docType package
+#' @name mockery
+#'
+#' @examples
+#' library(mockery)
+#' 
+#' m <- mock(TRUE, FALSE, TRUE)
+#' 
+#' # this will make summary call our mock function rather then
+#' # UseMethod; thus, summary() will return values as above
+#' stub(summary, 'UseMethod', m)
+#' 
+#' summary(iris) # returns TRUE
+#' summary(cars) # returns FALSE
+#' summary(co2)  # returns TRUE
+#' 
+#' \dontrun{
+#' library(testthat)
+#' 
+#' m <- mock(TRUE)
+#' f <- function() read.csv('data.csv')
+#' 
+#' with_mock(read.csv = m, {
+#'   f()
+#'   expect_call(m, 1, read.csv('data.csv'))
+#' })
+#' }
+NULL
\ No newline at end of file
diff --git a/R/stub.R b/R/stub.R
new file mode 100644
index 0000000..c9319e8
--- /dev/null
+++ b/R/stub.R
@@ -0,0 +1,169 @@
+
+#' Replace a function with a stub.
+#'
+#' The result of calling \code{stub} is that, when \code{where}
+#' is invoked and when it internally makes a call to \code{what},
+#' \code{how} is going to be called instead.
+#' 
+#' This is much more limited in scope in comparison to
+#' \code{\link[testthat]{with_mock}} which effectively replaces
+#' \code{what} everywhere. In other words, when using \code{with_mock}
+#' and regardless of the number of intermediate calls, \code{how} is
+#' always called instead of \code{what}. However, using this API,
+#' the replacement takes place only for a single function \code{where}
+#' and only for calls originating in that function.
+#' 
+#' 
+#' @name stub
+#' @rdname stub
+NULL
+
+# \code{remote_stub} reverses the effect of \code{stub}.
+
+
+#' @param where Function to be called that will in turn call
+#'        \code{what}.
+#' @param what Name of the function you want to stub out (a
+#'        \code{character} string).
+#' @param how Replacement function (also a \code{\link{mock}} function)
+#'        or a return value for which a function will be created
+#'        automatically.
+#' @param depth Specifies the depth to which the function should be stubbed
+#' 
+#' @export
+#' @rdname stub
+#' 
+#' @examples
+#' f <- function() TRUE
+#' g <- function() f()
+#' stub(g, 'f', FALSE)
+#' 
+#' # now g() returns FALSE because f() has been stubbed out
+#' g()
+#' 
+`stub` <- function (where, what, how, depth=1)
+{
+    # `where` needs to be a function
+    where_name <- deparse(substitute(where))
+  
+    # `what` needs to be a character value
+    stopifnot(is.character(what), length(what) == 1)
+
+    test_env <- parent.frame()
+    tree <- build_function_tree(test_env, where, where_name, depth)
+
+    mock_through_tree(tree, what, how)
+}
+
+mock_through_tree <- function(tree, what, how) {
+    for (d in tree) {
+        for (parent in d) {
+            parent_env = parent[['parent_env']]
+            func_dict = parent[['funcs']]
+            for (func_name in ls(func_dict, all.names=TRUE)) {
+                func = func_dict[[func_name]]
+                func_env = new.env(parent = environment(func))
+
+                what <- override_seperators(what, func_env)
+                where_name <- override_seperators(func_name, parent_env)
+
+                if (!is.function(how)) {
+                    assign(what, function(...) how, func_env)
+                } else {
+                    assign(what, how, func_env)
+                }
+
+                environment(func) <- func_env
+                assign(where_name, func, parent_env)
+            }
+        }
+  }
+}
+
+override_seperators = function(name, env) {
+    for (sep in c('::', "\\$")) {
+        if (grepl(sep, name)) {
+            elements <- strsplit(name, sep)
+            mangled_name <- paste(elements[[1]][1], elements[[1]][2], sep='XXX')
+
+            if (sep == '\\$') {
+                sep <- '$'
+            }
+
+            stub_list <- c(mangled_name)
+            if ("stub_list" %in% names(attributes(get(sep, env)))) {
+                stub_list <- c(stub_list, attributes(get(sep, env))[['stub_list']])
+            }
+
+            create_new_name <- create_create_new_name_function(stub_list, env, sep)
+            assign(sep, create_new_name, env)
+        }
+    }
+    return(if (exists('mangled_name')) mangled_name else name)
+}
+
+create_create_new_name_function <- function(stub_list, env, sep)
+{
+    force(stub_list)
+    force(env)
+    force(sep)
+
+    create_new_name <- function(pkg, func)
+    {
+        pkg_name  <- deparse(substitute(pkg))
+        func_name <- deparse(substitute(func))
+        for(stub in stub_list) {
+            if (paste(pkg_name, func_name, sep='XXX') == stub) {
+                return(eval(parse(text = stub), env))
+            }
+        }
+
+        # used to avoid recursively calling the replacement function
+        eval_env = new.env(parent=parent.frame())
+        assign(sep, eval(parse(text=paste0('`', sep, '`'))), eval_env)
+
+        code = paste(pkg_name, func_name, sep=sep)
+        return(eval(parse(text=code), eval_env))
+    }
+    attributes(create_new_name) <- list(stub_list=stub_list)
+    return(create_new_name)
+}
+
+build_function_tree <- function(test_env, where, where_name, depth)
+{
+    func_dict = new.env()
+    func_dict[[where_name]] = where
+    tree = list(
+        # one depth
+        list(
+            # one parent
+            list(parent_env=test_env, funcs=func_dict)
+        )
+    )
+
+    if (depth > 1) {
+        for (d in 2:depth) {
+            num_parents = 0
+            new_depth = list()
+            for (funcs in tree[[d - 1]]) {
+                parent_dict = funcs[['funcs']]
+                for (parent_name in ls(parent_dict, all.names=TRUE)) {
+                    func_dict = new.env()
+                    parent_env = environment(get(parent_name, parent_dict))
+                    for (func_name in ls(parent_env, all.names=TRUE)) {
+                        func = get(func_name, parent_env)
+                        if (is.function(func)) {
+                            func_dict[[func_name]] = func
+                        }
+                    }
+
+                    new_parent = list(parent_env=parent_env, funcs=func_dict)
+                    num_parents = num_parents + 1
+                    new_depth[[num_parents]] = new_parent
+                }
+            }
+            tree[[d]] = new_depth
+        }
+    }
+    return(tree)
+}
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..d1e70c9
--- /dev/null
+++ b/README.md
@@ -0,0 +1,153 @@
+# mockery
+[![Travis-CI Build Status](https://travis-ci.org/n-s-f/mockery.svg?branch=master)](https://travis-ci.org/n-s-f/mockery)
+[![Coverage Status](https://img.shields.io/codecov/c/github/n-s-f/mockery/master.svg)](https://codecov.io/github/n-s-f/mockery?branch=master)
+[![CRAN version](http://www.r-pkg.org/badges/version/mockery)](https://cran.r-project.org/package=mockery)
+
+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:
+> library('devtools')
+> devtools::install_github('n-s-f/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 = g(5)
+    expect_equal(result, 101)
+
+    # and allow you to make assertions on the mock was treated
+    expect_called(mock, 1)
+    expect_args(mock, 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.
diff --git a/build/vignette.rds b/build/vignette.rds
new file mode 100644
index 0000000..671f18b
Binary files /dev/null and b/build/vignette.rds differ
diff --git a/inst/doc/mocks-and-testthat.R b/inst/doc/mocks-and-testthat.R
new file mode 100644
index 0000000..e04e3d6
--- /dev/null
+++ b/inst/doc/mocks-and-testthat.R
@@ -0,0 +1,126 @@
+## ----include=FALSE-------------------------------------------------------
+library(mockery)
+
+library(knitr)
+knitr::opts_chunk$set(collapse = TRUE, comment = "#>")
+
+## ----create_mock---------------------------------------------------------
+m <- mock()
+
+## ----return_values-------------------------------------------------------
+m <- mock(1, 2, 3)
+m()
+m()
+m()
+
+## ----return_expression---------------------------------------------------
+x <- 1
+y <- 2
+m <- mock(x + y)
+m()
+
+## ----cycle_no, eval=FALSE------------------------------------------------
+#  m <- mock(1, 2)
+#  m()
+#  #> [1] 1
+#  m()
+#  #> [1] 2
+#  m()
+#  #> Error: too many calls to mock object and cycle set to FALSE
+
+## ----cycle_true----------------------------------------------------------
+m <- mock(1, 2, cycle = TRUE)
+m()
+m()
+m()
+m()
+
+## ----cycle_expression----------------------------------------------------
+x <- 1
+y <- 2
+m <- mock(1, x + y, cycle = TRUE)
+
+m()
+m()
+
+## ----cycle_expression_2nd------------------------------------------------
+y <- 10
+m()
+m()
+
+## ----return_expression_env-----------------------------------------------
+x <- 1
+y <- 2
+e <- new.env()
+m <- mock(x + y, envir = e, cycle = TRUE)
+
+m()
+e$x <- 10
+m()
+
+## ----with_mock, message=FALSE--------------------------------------------
+library(testthat)
+
+m <- mock(1)
+f <- function (x) summary(x)
+with_mock(f = m, {
+  expect_equal(f(iris), 1)
+})
+
+## ----expect_called-------------------------------------------------------
+m <- mock(1, 2)
+
+m()
+expect_called(m, 1)
+
+m()
+expect_called(m, 2)
+
+## ----expect_called_error, eval=FALSE-------------------------------------
+#  expect_called(m, 1)
+#  #> Error: mock object has not been called 1 time.
+#  expect_called(m, 3)
+#  #> Error: mock object has not been called 3 times.
+
+## ----expect_call---------------------------------------------------------
+m <- mock(1)
+with_mock(summary = m, {
+  summary(iris)
+})
+
+expect_call(m, 1, summary(iris))
+
+## ----call_doesnt_match, eval=FALSE---------------------------------------
+#  expect_call(m, 1, summary(x))
+#  #> Error: expected call summary(x) does not mach actual call summary(iris).
+
+## ----expect_args---------------------------------------------------------
+expect_args(m, 1, iris)
+
+## ----expect_args_different, eval=FALSE-----------------------------------
+#  expect_args(m, 1, iris[-1, ])
+#  #> Error: arguments to call #1 not equal to expected arguments.
+#  #> Component 1: Attributes: < Component "row.names": Numeric: lengths (150, 149) differ >
+#  #> Component 1: Component 1: Numeric: lengths (150, 149) differ
+#  #> Component 1: Component 2: Numeric: lengths (150, 149) differ
+#  #> Component 1: Component 3: Numeric: lengths (150, 149) differ
+#  #> Component 1: Component 4: Numeric: lengths (150, 149) differ
+#  #> Component 1: Component 5: Lengths: 150, 149
+#  #> Component 1: Component 5: Lengths (150, 149) differ (string compare on first 149)
+#  #> Component 1: Component 5: 2 string mismatches
+#  #> expected argument list does not mach actual one.
+
+## ----expect_args_named---------------------------------------------------
+m <- mock(1)
+with_mock(summary = m, {
+  summary(object = iris)
+})
+
+expect_args(m, 1, object = iris)
+
+## ----expect_args_unnamed, eval=FALSE-------------------------------------
+#  expect_args(m, 1, iris)
+#  #> Error: arguments to call #1 not equal to expected arguments.
+#  #> names for target but not for current
+#  #> expected argument list does not mach actual one.
+
diff --git a/inst/doc/mocks-and-testthat.Rmd b/inst/doc/mocks-and-testthat.Rmd
new file mode 100644
index 0000000..7609b58
--- /dev/null
+++ b/inst/doc/mocks-and-testthat.Rmd
@@ -0,0 +1,252 @@
+---
+title: 'Mocks: Integrating with `testthat`'
+author: "Lukasz A. Bartnik"
+date: "`r Sys.Date()`"
+output: rmarkdown::html_vignette
+vignette: >
+  %\VignetteIndexEntry{Mocks: Integrating with testthat}
+  %\VignetteEngine{knitr::rmarkdown}
+  %\VignetteEncoding{UTF-8}
+---
+
+```{r include=FALSE}
+library(mockery)
+
+library(knitr)
+knitr::opts_chunk$set(collapse = TRUE, comment = "#>")
+```
+
+
+Mock object, which is a part of the `mockery` package, started as an
+extension to [testthat](github.com/hadley/testthat)'s `with_mock()`
+facility. Its main purpose was to simplify the replacement (mocking)
+of a given function by means of `with_mock` and the later
+verification of actual calls invoked on the replacing function.
+
+The `mockery` package which provides its own stubbing facility, the
+`stub()` function. Here, however, we will look only at how `mock()`
+can be used together with `with_mock()`.
+
+
+## Mocks
+
+### Creating a `mock` function
+
+Mocking is a well-known technique when it comes to unit-testing and in
+most languages there is some notion of a mock object. In R, however, the
+natural equivalent of a mock object is a mock _function_ - and this is
+exactly what a call to `mock()` will produce.
+
+```{r create_mock}
+m <- mock()
+```
+
+
+### Return values
+
+Let's look at arguments accepted by the `mock()` _factory_ function. The
+main is a list of values which will be returned upon subsequent calls to
+`m`.
+
+```{r return_values}
+m <- mock(1, 2, 3)
+m()
+m()
+m()
+```
+
+`mock()` can take also an expression which will be evaluated upon a call.
+
+```{r return_expression}
+x <- 1
+y <- 2
+m <- mock(x + y)
+m()
+```
+
+
+### Cycling through return values
+
+By default, if the total number of calls exceeds the number of defined
+return values, the _mock_ function will throw an exception. However, one
+can also choose to cycle through the list of retun values by setting the
+`cycle` argument of `mock()` to `TRUE`.
+
+```{r cycle_no, eval=FALSE}
+m <- mock(1, 2)
+m()
+#> [1] 1
+m()
+#> [1] 2
+m()
+#> Error: too many calls to mock object and cycle set to FALSE
+```
+
+```{r cycle_true}
+m <- mock(1, 2, cycle = TRUE)
+m()
+m()
+m()
+m()
+```
+
+
+If a return value is defined by an expression, this expression will be
+evaluated each time a cycle reaches its position.
+
+```{r cycle_expression}
+x <- 1
+y <- 2
+m <- mock(1, x + y, cycle = TRUE)
+
+m()
+m()
+```
+```{r cycle_expression_2nd}
+y <- 10
+m()
+m()
+```
+
+
+### Evaluating expression in an environment of choice
+
+Finally, one can specify the environment where the return expression is
+evaluated.
+
+```{r return_expression_env}
+x <- 1
+y <- 2
+e <- new.env()
+m <- mock(x + y, envir = e, cycle = TRUE)
+
+m()
+e$x <- 10
+m()
+```
+
+
+## Integration with `with_mock()`
+
+### Simple integration
+
+Using mock functions with `testthat`'s `with_mock()` is pretty
+straightforward.
+
+```{r with_mock, message=FALSE}
+library(testthat)
+
+m <- mock(1)
+f <- function (x) summary(x)
+with_mock(f = m, {
+  expect_equal(f(iris), 1)
+})
+```
+
+
+### Verifying the number of calls
+
+The `mockery` package comes with a few additional expectations which
+might turn out to be a very useful extension to `testthat`'s API. One
+can for example verify the number and signature of calls invoked on a
+mock function, as well as the values of arguments passed in those calls.
+
+First, let's make sure the mocked function is called exactly as many
+times as we expect. This can be done with `expect_called()`.
+
+```{r expect_called}
+m <- mock(1, 2)
+
+m()
+expect_called(m, 1)
+
+m()
+expect_called(m, 2)
+```
+
+And here is what happens when we get the number of calls wrong.
+
+```{r expect_called_error, eval=FALSE}
+expect_called(m, 1)
+#> Error: mock object has not been called 1 time.
+expect_called(m, 3)
+#> Error: mock object has not been called 3 times.
+```
+
+### Verify the call signature
+
+Another new expectation is `expect_call()` which compares the signature
+of the actual call as invoked on the mock function with the expected one.
+It takes as arguments: the mock function, the call number, expected call.
+
+```{r expect_call}
+m <- mock(1)
+with_mock(summary = m, {
+  summary(iris)
+})
+
+expect_call(m, 1, summary(iris))
+```
+
+And here is what happens if the call doesn't match.
+
+```{r call_doesnt_match, eval=FALSE}
+expect_call(m, 1, summary(x))
+#> Error: expected call summary(x) does not mach actual call summary(iris).
+```
+
+### Verify values of argument
+
+Finally, one can verify whether the actual values of arguments passed
+to the mock function match the expectation. Following the previous
+example of `summary(iris)` we can make sure that the `object` parameter
+passed to `m()` was actually the `iris` dataset.
+
+```{r expect_args}
+expect_args(m, 1, iris)
+```
+
+Here is what happens if the value turns out to be different.
+
+```{r expect_args_different, eval=FALSE}
+expect_args(m, 1, iris[-1, ])
+#> Error: arguments to call #1 not equal to expected arguments.
+#> Component 1: Attributes: < Component "row.names": Numeric: lengths (150, 149) differ >
+#> Component 1: Component 1: Numeric: lengths (150, 149) differ
+#> Component 1: Component 2: Numeric: lengths (150, 149) differ
+#> Component 1: Component 3: Numeric: lengths (150, 149) differ
+#> Component 1: Component 4: Numeric: lengths (150, 149) differ
+#> Component 1: Component 5: Lengths: 150, 149
+#> Component 1: Component 5: Lengths (150, 149) differ (string compare on first 149)
+#> Component 1: Component 5: 2 string mismatches
+#> expected argument list does not mach actual one.
+```
+
+If the call has been made with an explicit argument name the same has
+to appear in `expect_args()`.
+
+```{r expect_args_named}
+m <- mock(1)
+with_mock(summary = m, {
+  summary(object = iris)
+})
+
+expect_args(m, 1, object = iris)
+```
+
+Omitting the name results in an error.
+
+```{r expect_args_unnamed, eval=FALSE}
+expect_args(m, 1, iris)
+#> Error: arguments to call #1 not equal to expected arguments.
+#> names for target but not for current
+#> expected argument list does not mach actual one.
+```
+
+
+## Further reading
+
+More information can be found in examples presented in manual pages
+for `?mock` and `?expect_call`. Extensive information about testing
+in R can be found in the documentation for the
+[testthat](github.com/hadley/testthat) package.
diff --git a/inst/doc/mocks-and-testthat.html b/inst/doc/mocks-and-testthat.html
new file mode 100644
index 0000000..ec87bdd
--- /dev/null
+++ b/inst/doc/mocks-and-testthat.html
@@ -0,0 +1,434 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
+
+<title>Mocks</title>
+
+<script type="text/javascript">
+window.onload = function() {
+  var imgs = document.getElementsByTagName('img'), i, img;
+  for (i = 0; i < imgs.length; i++) {
+    img = imgs[i];
+    // center an image if it is the only element of its parent
+    if (img.parentElement.childElementCount === 1)
+      img.parentElement.style.textAlign = 'center';
+  }
+};
+</script>
+
+<!-- Styles for R syntax highlighter -->
+<style type="text/css">
+   pre .operator,
+   pre .paren {
+     color: rgb(104, 118, 135)
+   }
+
+   pre .literal {
+     color: #990073
+   }
+
+   pre .number {
+     color: #099;
+   }
+
+   pre .comment {
+     color: #998;
+     font-style: italic
+   }
+
+   pre .keyword {
+     color: #900;
+     font-weight: bold
+   }
+
+   pre .identifier {
+     color: rgb(0, 0, 0);
+   }
+
+   pre .string {
+     color: #d14;
+   }
+</style>
+
+<!-- R syntax highlighter -->
+<script type="text/javascript">
+var hljs=new function(){function m(p){return p.replace(/&/gm,"&").replace(/</gm,"<")}function f(r,q,p){return RegExp(q,"m"+(r.cI?"i":"")+(p?"g":""))}function b(r){for(var p=0;p<r.childNodes.length;p++){var q=r.childNodes[p];if(q.nodeName=="CODE"){return q}if(!(q.nodeType==3&&q.nodeValue.match(/\s+/))){break}}}function h(t,s){var p="";for(var r=0;r<t.childNodes.length;r++){if(t.childNodes[r].nodeType==3){var q=t.childNodes[r].nodeValue;if(s){q=q.replace(/\n/g,"")}p+=q}else{if(t.chi [...]
+hljs.initHighlightingOnLoad();
+</script>
+
+
+
+<style type="text/css">
+body, td {
+   font-family: sans-serif;
+   background-color: white;
+   font-size: 13px;
+}
+
+body {
+  max-width: 800px;
+  margin: auto;
+  padding: 1em;
+  line-height: 20px;
+}
+
+tt, code, pre {
+   font-family: 'DejaVu Sans Mono', 'Droid Sans Mono', 'Lucida Console', Consolas, Monaco, monospace;
+}
+
+h1 {
+   font-size:2.2em;
+}
+
+h2 {
+   font-size:1.8em;
+}
+
+h3 {
+   font-size:1.4em;
+}
+
+h4 {
+   font-size:1.0em;
+}
+
+h5 {
+   font-size:0.9em;
+}
+
+h6 {
+   font-size:0.8em;
+}
+
+a:visited {
+   color: rgb(50%, 0%, 50%);
+}
+
+pre, img {
+  max-width: 100%;
+}
+pre {
+  overflow-x: auto;
+}
+pre code {
+   display: block; padding: 0.5em;
+}
+
+code {
+  font-size: 92%;
+  border: 1px solid #ccc;
+}
+
+code[class] {
+  background-color: #F8F8F8;
+}
+
+table, td, th {
+  border: none;
+}
+
+blockquote {
+   color:#666666;
+   margin:0;
+   padding-left: 1em;
+   border-left: 0.5em #EEE solid;
+}
+
+hr {
+   height: 0px;
+   border-bottom: none;
+   border-top-width: thin;
+   border-top-style: dotted;
+   border-top-color: #999999;
+}
+
+ at media print {
+   * {
+      background: transparent !important;
+      color: black !important;
+      filter:none !important;
+      -ms-filter: none !important;
+   }
+
+   body {
+      font-size:12pt;
+      max-width:100%;
+   }
+
+   a, a:visited {
+      text-decoration: underline;
+   }
+
+   hr {
+      visibility: hidden;
+      page-break-before: always;
+   }
+
+   pre, blockquote {
+      padding-right: 1em;
+      page-break-inside: avoid;
+   }
+
+   tr, img {
+      page-break-inside: avoid;
+   }
+
+   img {
+      max-width: 100% !important;
+   }
+
+   @page :left {
+      margin: 15mm 20mm 15mm 10mm;
+   }
+
+   @page :right {
+      margin: 15mm 10mm 15mm 20mm;
+   }
+
+   p, h2, h3 {
+      orphans: 3; widows: 3;
+   }
+
+   h2, h3 {
+      page-break-after: avoid;
+   }
+}
+</style>
+
+
+
+</head>
+
+<body>
+<p>Mock object, which is a part of the <code>mockery</code> package, started as an
+extension to <a href="github.com/hadley/testthat">testthat</a>'s <code>with_mock()</code>
+facility. Its main purpose was to simplify the replacement (mocking)
+of a given function by means of <code>with_mock</code> and the later
+verification of actual calls invoked on the replacing function.</p>
+
+<p>The <code>mockery</code> package which provides its own stubbing facility, the
+<code>stub()</code> function. Here, however, we will look only at how <code>mock()</code>
+can be used together with <code>with_mock()</code>.</p>
+
+<h2>Mocks</h2>
+
+<h3>Creating a <code>mock</code> function</h3>
+
+<p>Mocking is a well-known technique when it comes to unit-testing and in
+most languages there is some notion of a mock object. In R, however, the
+natural equivalent of a mock object is a mock <em>function</em> - and this is
+exactly what a call to <code>mock()</code> will produce.</p>
+
+<pre><code class="r">m <- mock()
+</code></pre>
+
+<h3>Return values</h3>
+
+<p>Let's look at arguments accepted by the <code>mock()</code> <em>factory</em> function. The
+main is a list of values which will be returned upon subsequent calls to
+<code>m</code>.</p>
+
+<pre><code class="r">m <- mock(1, 2, 3)
+m()
+#> [1] 1
+m()
+#> [1] 2
+m()
+#> [1] 3
+</code></pre>
+
+<p><code>mock()</code> can take also an expression which will be evaluated upon a call.</p>
+
+<pre><code class="r">x <- 1
+y <- 2
+m <- mock(x + y)
+m()
+#> [1] 3
+</code></pre>
+
+<h3>Cycling through return values</h3>
+
+<p>By default, if the total number of calls exceeds the number of defined
+return values, the <em>mock</em> function will throw an exception. However, one
+can also choose to cycle through the list of retun values by setting the
+<code>cycle</code> argument of <code>mock()</code> to <code>TRUE</code>.</p>
+
+<pre><code class="r">m <- mock(1, 2)
+m()
+#> [1] 1
+m()
+#> [1] 2
+m()
+#> Error: too many calls to mock object and cycle set to FALSE
+</code></pre>
+
+<pre><code class="r">m <- mock(1, 2, cycle = TRUE)
+m()
+#> [1] 1
+m()
+#> [1] 2
+m()
+#> [1] 1
+m()
+#> [1] 2
+</code></pre>
+
+<p>If a return value is defined by an expression, this expression will be
+evaluated each time a cycle reaches its position.</p>
+
+<pre><code class="r">x <- 1
+y <- 2
+m <- mock(1, x + y, cycle = TRUE)
+
+m()
+#> [1] 1
+m()
+#> [1] 3
+</code></pre>
+
+<pre><code class="r">y <- 10
+m()
+#> [1] 1
+m()
+#> [1] 11
+</code></pre>
+
+<h3>Evaluating expression in an environment of choice</h3>
+
+<p>Finally, one can specify the environment where the return expression is
+evaluated.</p>
+
+<pre><code class="r">x <- 1
+y <- 2
+e <- new.env()
+m <- mock(x + y, envir = e, cycle = TRUE)
+
+m()
+#> [1] 3
+e$x <- 10
+m()
+#> [1] 12
+</code></pre>
+
+<h2>Integration with <code>with_mock()</code></h2>
+
+<h3>Simple integration</h3>
+
+<p>Using mock functions with <code>testthat</code>'s <code>with_mock()</code> is pretty
+straightforward.</p>
+
+<pre><code class="r">library(testthat)
+
+m <- mock(1)
+f <- function (x) summary(x)
+with_mock(f = m, {
+  expect_equal(f(iris), 1)
+})
+</code></pre>
+
+<h3>Verifying the number of calls</h3>
+
+<p>The <code>mockery</code> package comes with a few additional expectations which
+might turn out to be a very useful extension to <code>testthat</code>'s API. One
+can for example verify the number and signature of calls invoked on a
+mock function, as well as the values of arguments passed in those calls.</p>
+
+<p>First, let's make sure the mocked function is called exactly as many
+times as we expect. This can be done with <code>expect_called()</code>.</p>
+
+<pre><code class="r">m <- mock(1, 2)
+
+m()
+#> [1] 1
+expect_called(m, 1)
+
+m()
+#> [1] 2
+expect_called(m, 2)
+</code></pre>
+
+<p>And here is what happens when we get the number of calls wrong.</p>
+
+<pre><code class="r">expect_called(m, 1)
+#> Error: mock object has not been called 1 time.
+expect_called(m, 3)
+#> Error: mock object has not been called 3 times.
+</code></pre>
+
+<h3>Verify the call signature</h3>
+
+<p>Another new expectation is <code>expect_call()</code> which compares the signature
+of the actual call as invoked on the mock function with the expected one.
+It takes as arguments: the mock function, the call number, expected call.</p>
+
+<pre><code class="r">m <- mock(1)
+with_mock(summary = m, {
+  summary(iris)
+})
+#> [1] 1
+
+expect_call(m, 1, summary(iris))
+</code></pre>
+
+<p>And here is what happens if the call doesn't match.</p>
+
+<pre><code class="r">expect_call(m, 1, summary(x))
+#> Error: expected call summary(x) does not mach actual call summary(iris).
+</code></pre>
+
+<h3>Verify values of argument</h3>
+
+<p>Finally, one can verify whether the actual values of arguments passed
+to the mock function match the expectation. Following the previous
+example of <code>summary(iris)</code> we can make sure that the <code>object</code> parameter
+passed to <code>m()</code> was actually the <code>iris</code> dataset.</p>
+
+<pre><code class="r">expect_args(m, 1, iris)
+</code></pre>
+
+<p>Here is what happens if the value turns out to be different.</p>
+
+<pre><code class="r">expect_args(m, 1, iris[-1, ])
+#> Error: arguments to call #1 not equal to expected arguments.
+#> Component 1: Attributes: < Component "row.names": Numeric: lengths (150, 149) differ >
+#> Component 1: Component 1: Numeric: lengths (150, 149) differ
+#> Component 1: Component 2: Numeric: lengths (150, 149) differ
+#> Component 1: Component 3: Numeric: lengths (150, 149) differ
+#> Component 1: Component 4: Numeric: lengths (150, 149) differ
+#> Component 1: Component 5: Lengths: 150, 149
+#> Component 1: Component 5: Lengths (150, 149) differ (string compare on first 149)
+#> Component 1: Component 5: 2 string mismatches
+#> expected argument list does not mach actual one.
+</code></pre>
+
+<p>If the call has been made with an explicit argument name the same has
+to appear in <code>expect_args()</code>.</p>
+
+<pre><code class="r">m <- mock(1)
+with_mock(summary = m, {
+  summary(object = iris)
+})
+#> [1] 1
+
+expect_args(m, 1, object = iris)
+</code></pre>
+
+<p>Omitting the name results in an error.</p>
+
+<pre><code class="r">expect_args(m, 1, iris)
+#> Error: arguments to call #1 not equal to expected arguments.
+#> names for target but not for current
+#> expected argument list does not mach actual one.
+</code></pre>
+
+<h2>Further reading</h2>
+
+<p>More information can be found in examples presented in manual pages
+for <code>?mock</code> and <code>?expect_call</code>. Extensive information about testing
+in R can be found in the documentation for the
+<a href="github.com/hadley/testthat">testthat</a> package.</p>
+
+</body>
+
+</html>
diff --git a/man/call-expectations.Rd b/man/call-expectations.Rd
new file mode 100644
index 0000000..c1176a8
--- /dev/null
+++ b/man/call-expectations.Rd
@@ -0,0 +1,55 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/expectations.R
+\name{call-expectations}
+\alias{call-expectations}
+\alias{expect_call}
+\alias{expect_args}
+\alias{expect_called}
+\title{Expectation: does the given call match the expected?}
+\usage{
+expect_call(mock_object, n, expected_call)
+
+expect_args(mock_object, n, ...)
+
+expect_called(mock_object, n)
+}
+\arguments{
+\item{mock_object}{A \code{\link{mock}} object.}
+
+\item{n}{Call number or total number of calls.}
+
+\item{expected_call}{Expected call expression; will be compared unevaluated.}
+
+\item{...}{Arguments as passed in a call.}
+}
+\description{
+Together with \code{\link{mock}} can be used to verify whether the
+call expression (\code{\link{expect_call}}) and/or argument values
+(\code{\link{expect_args}}) match the expected.
+}
+\details{
+With \code{expect_called} you can check how many times has the mock
+object been called.
+}
+\examples{
+library(testthat)
+
+# expect call expression (signature)
+m <- mock()
+with_mock(summary = m, summary(iris))
+
+# it has been called once
+expect_called(m, 1)
+
+# the first (and only) call's arguments matches summary(iris)
+expect_call(m, 1, summary(iris))
+
+# expect argument value
+m <- mock()
+a <- iris
+with_mock(summary = m, summary(object = a))
+expect_args(m, 1, object = a)
+# is an equivalent to ...
+expect_equal(mock_args(m)[[1]], list(object = a))
+
+}
diff --git a/man/mock.Rd b/man/mock.Rd
new file mode 100644
index 0000000..b8d8013
--- /dev/null
+++ b/man/mock.Rd
@@ -0,0 +1,106 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/mock-object.R
+\name{mock}
+\alias{mock}
+\alias{mock}
+\alias{mock_args}
+\alias{mock_calls}
+\alias{length.mock}
+\title{Create and query a mocked function.}
+\usage{
+mock(..., cycle = FALSE, envir = parent.frame())
+
+mock_args(m)
+
+mock_calls(m)
+
+\method{length}{mock}(x)
+}
+\arguments{
+\item{...}{Values returned upon subsequent calls.}
+
+\item{cycle}{Whether to cycle over the return values. If \code{FALSE},
+will fail if called too many times.}
+
+\item{envir}{Where to evaluate the expressions being returned.}
+
+\item{m}{A \code{\link{mock}}ed function.}
+
+\item{x}{A \code{\link{mock}}ed function.}
+}
+\value{
+\code{mock()} returns a mocked function which can be then used
+        with \code{\link{with_mock}}.
+
+\code{mock_args()} returns a \code{list} of \code{list}s
+        of argument values.
+
+\code{mock_calls()} returns a \code{list} of \code{call}s.
+
+\code{length.mock()} returns the number of calls invoked on \code{m}.
+}
+\description{
+Mock object's primary use is to record calls that are made on the
+mocked function.
+}
+\details{
+Optionally values/expressions can be passed via \code{...} for the
+mock object to return them upon subsequent calls. Expressions are
+evaluated in environment \code{envir} before being returned. If no
+value is passed in \code{...} then \code{NULL} is returned.
+
+Passing an expression or a function call via \code{...} is also a
+way to implement side effects: keep track of the state of code
+under testing, throw an exception when a condition is met, etc.
+
+\code{mock_calls} and \code{mock_args} can be used to access the
+list of calls made on a mocked function and a respective list of
+values of arguments passed to each of these calls.
+}
+\examples{
+library(testthat)
+
+m <- mock(1)
+with_mock(summary = m, {
+  expect_equal(summary(iris), 1)
+  expect_called(m, 1)
+  expect_call(m, 1, summary(iris))
+  expect_args(m, 1, iris)
+})
+
+# multiple return values
+m <- mock(1, "a", sqrt(3))
+with_mock(summary = m, {
+  expect_equal(summary(iris), 1)
+  expect_equal(summary(iris), "a")
+  expect_equal(summary(iris), 1.73, tolerance = .01)
+})
+
+# side effects
+m <- mock(1, 2, stop("error"))
+with_mock(summary = m, {
+  expect_equal(summary(iris), 1)
+  expect_equal(summary(iris), 2)
+  expect_error(summary(iris), "error")
+})
+
+# accessing call expressions
+m <- mock()
+m(x = 1)
+m(y = 2)
+expect_equal(length(m), 2)
+calls <- mock_calls(m)
+expect_equal(calls[[1]], quote(m(x = 1)))
+expect_equal(calls[[2]], quote(m(y = 2)))
+
+# accessing values of arguments
+m <- mock()
+m(x = 1)
+m(y = 2)
+expect_equal(length(m), 2)
+args <- mock_args(m)
+expect_equal(args[[1]], list(x = 1))
+expect_equal(args[[2]], list(y = 2))
+
+
+}
diff --git a/man/mockery.Rd b/man/mockery.Rd
new file mode 100644
index 0000000..6984853
--- /dev/null
+++ b/man/mockery.Rd
@@ -0,0 +1,37 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/mockery.R
+\docType{package}
+\name{mockery}
+\alias{mockery}
+\alias{mockery-package}
+\title{R package to make mocking easier}
+\description{
+There are great tools for unit testing in R out there already but
+they don't come with a lot of support for mock objects. This
+package aims at fixing that.
+}
+\examples{
+library(mockery)
+
+m <- mock(TRUE, FALSE, TRUE)
+
+# this will make summary call our mock function rather then
+# UseMethod; thus, summary() will return values as above
+stub(summary, 'UseMethod', m)
+
+summary(iris) # returns TRUE
+summary(cars) # returns FALSE
+summary(co2)  # returns TRUE
+
+\dontrun{
+library(testthat)
+
+m <- mock(TRUE)
+f <- function() read.csv('data.csv')
+
+with_mock(read.csv = m, {
+  f()
+  expect_call(m, 1, read.csv('data.csv'))
+})
+}
+}
diff --git a/man/stub.Rd b/man/stub.Rd
new file mode 100644
index 0000000..e599b36
--- /dev/null
+++ b/man/stub.Rd
@@ -0,0 +1,45 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/stub.R
+\name{stub}
+\alias{stub}
+\alias{stub}
+\title{Replace a function with a stub.}
+\usage{
+stub(where, what, how, depth = 1)
+}
+\arguments{
+\item{where}{Function to be called that will in turn call
+\code{what}.}
+
+\item{what}{Name of the function you want to stub out (a
+\code{character} string).}
+
+\item{how}{Replacement function (also a \code{\link{mock}} function)
+or a return value for which a function will be created
+automatically.}
+
+\item{depth}{Specifies the depth to which the function should be stubbed}
+}
+\description{
+The result of calling \code{stub} is that, when \code{where}
+is invoked and when it internally makes a call to \code{what},
+\code{how} is going to be called instead.
+}
+\details{
+This is much more limited in scope in comparison to
+\code{\link[testthat]{with_mock}} which effectively replaces
+\code{what} everywhere. In other words, when using \code{with_mock}
+and regardless of the number of intermediate calls, \code{how} is
+always called instead of \code{what}. However, using this API,
+the replacement takes place only for a single function \code{where}
+and only for calls originating in that function.
+}
+\examples{
+f <- function() TRUE
+g <- function() f()
+stub(g, 'f', FALSE)
+
+# now g() returns FALSE because f() has been stubbed out
+g()
+
+}
diff --git a/tests/testthat.R b/tests/testthat.R
new file mode 100644
index 0000000..bdfcead
--- /dev/null
+++ b/tests/testthat.R
@@ -0,0 +1,4 @@
+library(testthat)
+library(mockery)
+
+test_check("mockery")
diff --git a/tests/testthat/test-mock-object.R b/tests/testthat/test-mock-object.R
new file mode 100644
index 0000000..b66817e
--- /dev/null
+++ b/tests/testthat/test-mock-object.R
@@ -0,0 +1,179 @@
+context("Mock objects")
+
+test_that("mock single brackets", {
+  m <- mock(1)
+  m()
+  expect_equal(mock_calls(m)[[1]], bquote(m()))
+})
+
+
+test_that("mock length", {
+  m <- mock(1, cycle = TRUE)
+  expect_equal(length(m), 0)
+
+  m()
+  expect_equal(length(m), 1)
+
+  m()
+  m()
+  expect_equal(length(m), 3)
+})
+
+
+test_that("mock cyclic returns", {
+  m <- mock(1, cycle = TRUE)
+  expect_equal(lapply(1:10, m), as.list(rep(1, 10)))
+
+  m <- mock(1, 2, cycle = TRUE)
+  expect_equal(lapply(1:10, m), as.list(rep(1:2, 5)))
+
+  m <- mock(1, 2, 3, cycle = TRUE)
+  expect_equal(lapply(1:12, m), as.list(rep(1:3, 4)))
+})
+
+
+test_that("call list", {
+  m <- mock()
+  e <- environment(m)
+
+  with_mock(summary = m, {
+    summary(iris)
+  })
+
+  expect_true(exists('calls', envir = e))
+  expect_length(e$calls, 1)
+  expect_equal(e$calls[[1]], bquote(summary(iris)))
+})
+
+
+test_that("expect calls", {
+  m <- mock()
+
+  with_mock(summary = m, {
+    summary(iris)
+  })
+
+  expect_call(m, 1, summary(iris))
+})
+
+
+test_that("error for long call is formatted well", {
+  m <- mock()
+  mockery::stub(read.csv, "read.table", m)
+  read.csv('file.csv')
+
+  # test mock with mock, how crazy is that!
+  # we cannot call expect_failure because it messes up calls to expect()
+  # thus we intercept calls to expect() and later compare arguments
+  test_mock <- mock(TRUE, TRUE)
+  with_mock(expect = test_mock, {
+    expect_call(m, 1, x)
+  })
+
+  expect_called(test_mock, 2)
+  
+  err <- paste0(
+    'expected call x does not mach actual call ',
+    'read.table(file = file, header = header, sep = sep, quote = quote, ',
+    'dec = dec, fill = fill, comment.char = comment.char).'
+  )
+  expect_args(test_mock, 2, FALSE, err)
+})
+
+test_that("empty return list", {
+  m <- mock()
+  expect_null(m())
+})
+
+
+test_that("too many calls", {
+  m <- mock(1)
+  expect_equal(1, m())
+  expect_failure(m(), "too many calls to mock object and cycle set to FALSE")
+})
+
+
+test_that("return expression", {
+  e <- new.env(parent = globalenv())
+  m <- mock(fun_x("a"),
+            fun_x("a") == "a",
+            envir = e, cycle = TRUE)
+
+  e$fun_x <- function(x)x
+  expect_equal(m(), "a")
+  expect_true(m())
+
+  e$fun_x <- function(x)"abc"
+  expect_equal(m(), "abc")
+  expect_false(m())
+})
+
+
+test_that("operator $ works for mock", {
+  m <- mock()
+  expect_equal(mock_calls(m), list())
+  expect_equal(mock_args(m), list())
+})
+
+
+test_that("arguments are recorded", {
+  m <- mock()
+  m(x = 1)
+  m(y = 2, z = iris)
+
+  expect_equal(length(m), 2)
+  expect_named(mock_args(m)[[1]], 'x')
+  expect_named(mock_args(m)[[2]], c('y', 'z'))
+
+  expect_equal(mock_args(m)[[1]]$x, 1)
+  expect_equal(mock_args(m)[[2]]$y, 2)
+  expect_equal(mock_args(m)[[2]]$z, iris)
+})
+
+
+test_that("expect args", {
+  m <- mock()
+  m(iris)
+  m(x = 1)
+
+  # compares values, not symbols
+  y <- 2
+  z <- iris
+  m(y = y, z = z)
+
+  expect_args(m, 1, iris)
+  expect_args(m, 2, x = 1)
+  expect_args(m, 3, y = 2, z = iris)
+})
+
+
+test_that("expect args in with_mock", {
+  m <- mock()
+
+  with_mock(lm = m, {
+    x <- iris
+    lm(Sepal.Width ~ Sepal.Length, data = x)
+  })
+
+  expect_args(m, 1, Sepal.Width ~ Sepal.Length, data = iris)
+})
+
+
+test_that("calls are counted", {
+  m <- mock()
+  expect_called(m, 0)
+
+  m()
+  expect_called(m, 1)
+
+  m()
+  expect_called(m, 2)
+})
+
+
+test_that("appropriate message if counts are missing", {
+  m <- mock()
+  expect_failure(expect_called(m, 1), "mock object has not been called 1 time")
+  expect_failure(expect_called(m, 2), "mock object has not been called 2 times")
+})
+
diff --git a/tests/testthat/test_stub.R b/tests/testthat/test_stub.R
new file mode 100644
index 0000000..43275b7
--- /dev/null
+++ b/tests/testthat/test_stub.R
@@ -0,0 +1,332 @@
+testthat::context('stub')
+
+a = 10
+f = function(x) x
+g = function(x) f(x) + a
+test_that('stubs function with return value', {
+    # before stubbing
+    expect_equal(g(20), 30)
+
+    # when
+    stub(g, 'f', 100)
+
+    # then
+    expect_equal(g(20), 110)
+})
+
+test_that('values restored after test', {
+    expect_equal(f(15), 15)
+    expect_equal(g(15), 25)
+})
+
+test_that('stubs function with function', {
+    # given
+    a = 10
+    f = function(x) x
+    g = function(x) f(x) + a
+
+    # before stubbing
+    expect_equal(g(20), 30)
+
+    # when
+    stub(g, 'f', function(...) 500)
+
+    # then
+    expect_equal(g(10), 510)
+})
+
+
+test_that('stubs function from namespace', {
+    # given
+    f = function() testthat::capture_output(print('hello'))
+
+    # before stubbing
+    expect_true(grepl('hello', f()))
+
+    # when
+    stub(f, 'testthat::capture_output', 10)
+
+    # then
+    expect_equal(f(), 10)
+})
+
+test_that('does not stub other namespeaced functions', {
+    # given
+    f = function() {
+        a = testthat::capture_output(print('hello'))
+        b = testthat::is_null('not null')
+        return(c(a, b))
+    }
+
+    # when
+    stub(f, 'testthat::is_null', 'stubbed output')
+
+    # then
+    result = f()
+    expect_true(grepl('hello', result[1]))
+    expect_equal(result[2], 'stubbed output')
+})
+
+test_that('stub multiple functions', {
+    # given
+    f = function(x) x + 10
+    g = function(y) y + 20
+    h = function(z) f(z) + g(z)
+
+    # when
+    stub(h, 'f', 300)
+    stub(h, 'g', 500)
+
+    # then
+    expect_equal(h(1), 800)
+})
+
+test_that('stub multiple namespaced functions', {
+    # given
+    h = function(x) mockery::stub(x) + mockery::get_function_source(x)
+
+    # when
+    stub(h, 'mockery::stub', 300)
+    stub(h, 'mockery::get_function_source', 500)
+
+    # then
+    expect_equal(h(1), 800)
+})
+
+test_that('stub works with do.call', {
+    # given
+    f = function(x) x + 10
+    g = function(x) do.call('f', list(x))
+
+    # before stub
+    expect_equal(g(10), 20)
+
+    # stub
+    stub(g, 'f', 100)
+
+    # then
+    expect_equal(g(10), 100)
+})
+
+test_that('stub works with lapply', {
+    # given
+    f = function(x) x + 10
+    g = function(x) lapply(x, 'f')
+    l = list(1, 2, 3)
+
+    # before stub
+    expect_equal(g(l), list(11, 12, 13))
+
+    # stub
+    stub(g, 'f', 100)
+
+    # then
+    expect_equal(g(l), list(100, 100, 100))
+})
+
+test_that('stub works well with mock object', {
+    # given
+    f = function(x) x + 10
+    g = function(x) f(x)
+
+    mock_object = mock(100)
+    stub(g, 'f', mock_object)
+
+    # when
+    result = g(5)
+
+    # then
+    expect_equal(result, 100)
+})
+
+f = function(x) x + 10
+g = function(x) f(x)
+test_that('mock object returns value', {
+    mock_object = mock(1)
+    stub(g, 'f', mock_object)
+
+    expect_equal(g('anything'), 1)
+    expect_called(mock_object, 1)
+    expect_args(mock_object, 1, 'anything')
+})
+
+test_that('mock object multiple return values', {
+    mock_object = mock(1, "a", sqrt(3))
+    stub(g, 'f', mock_object)
+
+    expect_equal(g('anything'), 1)
+    expect_equal(g('anything'), "a")
+    expect_equal(g('anything'), sqrt(3))
+})
+
+test_that('mock object accessing values of arguments', {
+    mock_object <- mock()
+    mock_object(x = 1)
+    mock_object(y = 2)
+
+    expect_equal(length(mock_object), 2)
+    args <- mock_args(mock_object)
+
+    expect_equal(args[[1]], list(x = 1))
+    expect_equal(args[[2]], list(y = 2))
+})
+
+test_that('mock object accessing call expressions', {
+    mock_object <- mock()
+    mock_object(x = 1)
+    mock_object(y = 2)
+
+    expect_equal(length(mock_object), 2)
+    calls <- mock_calls(mock_object)
+
+    expect_equal(calls[[1]], quote(mock_object(x = 1)))
+    expect_equal(calls[[2]], quote(mock_object(y = 2)))
+})
+
+library(R6)
+
+some_other_class = R6Class("some_class",
+    public = list(
+        external_method = function() {return('this is external output')}
+    )
+)
+
+some_class = R6Class("some_class",
+    public = list(
+        some_method = function() {return(some_function())},
+        some_method_prime = function() {return(some_function())},
+        other_method = function() {return('method in class')},
+        method_without_other = function() { self$other_method() },
+        method_with_other = function() {
+          other <- some_other_class$new()
+          other$external_method()
+          self$other_method()
+        }
+    )
+)
+
+# Calling function from R6 method
+ some_function = function() {return("called from within class")}
+ obj = some_class$new()
+test_that('stub works with R6 methods', {
+    stub(obj$some_method, 'some_function', 'stub has been called')
+    expect_equal(obj$some_method(), 'stub has been called')
+})
+
+test_that('stub works with R6 methods that call internal methods in them', {
+    stub(obj$method_without_other, 'self$other_method', 'stub has been called')
+    expect_equal(obj$method_without_other(), 'stub has been called')
+})
+
+test_that('stub works with R6 methods that have other objects in them', {
+    stub(obj$method_with_other, 'self$other_method', 'stub has been called')
+    expect_equal(obj$method_with_other(), 'stub has been called')
+})
+
+test_that('R6 method does not stay stubbed', {
+    expect_equal(obj$some_method(), 'called from within class')
+})
+
+# Calling R6 method from function
+other_func = function() {
+    obj = some_class$new()
+    return(obj$other_method())
+}
+test_that('stub works for stubbing R6 methods from within function calls', {
+    stub(other_func, 'obj$other_method', 'stubbed R6 method')
+    expect_equal(other_func(), 'stubbed R6 method')
+})
+
+test_that('stub does not stay in effect', {
+    expect_equal(other_func(), 'method in class')
+})
+
+test_that('stub out of namespaced functions', {
+    expect_true(grepl('hello', testthat::capture_output(print('hello'))))
+    stub(testthat::capture_output, 'paste0', 'stubbed function')
+    expect_equal(testthat::capture_output(print('hello')), 'stubbed function')
+})
+
+test_that('stub multiple namespaced and R6 functions from within test env', {
+    stub(testthat::capture_output, 'paste0', 'stub 1')
+    stub(obj$some_method, 'some_function', 'stub 2')
+    stub(obj$some_method_prime, 'some_function', 'stub 3')
+    stub(testthat::test_that, 'test_code', 'stub 4')
+
+    # all stubs are active
+    expect_equal(testthat::capture_output(print('hello')), 'stub 1')
+    expect_equal(obj$some_method(), 'stub 2')
+    expect_equal(obj$some_method_prime(), 'stub 3')
+    expect_equal(testthat::test_that('a', print), 'stub 4')
+
+    # non mocked R6 and namespaced functions work as expected
+    expect_equal(obj$other_method(), 'method in class')
+    testthat::expect_failure(expect_equal(4, 5))
+})
+
+h = function(x) 'called h'
+g = function(x) h(x)
+f = function(x) g(x)
+test_that('use can specify depth of mocking', {
+    stub_string = 'called stub!'
+    stub(f, 'h', stub_string, depth=2)
+    expect_equal(f(1), stub_string)
+})
+
+h = function(x) 'called h'
+g = function(x) h(x)
+f = function(x) paste0(h(x), g(x))
+test_that('mocked function is mocked at all depths', {
+    stub_string = 'called stub!'
+    stub(f, 'h', stub_string, depth=2)
+    expect_equal(f(1), 'called stub!called stub!')
+})
+
+h = function(x) 'called h'
+g = function(x) h(x)
+r = function(x) g(x)
+f = function(x) paste0(h(x), r(x))
+test_that('mocked function is mocked at all depths', {
+    stub_string = 'called stub!'
+    stub(f, 'h', stub_string, depth=3)
+    expect_equal(f(1), 'called stub!called stub!')
+})
+
+h = function(x) 'called h'
+t = function(x) h(x)
+g = function(x) h(x)
+r = function(x) paste0(t(x), g(x))
+u = function(x) paste0(h(x), g(x))
+
+f = function(x) paste0(h(x), r(x), u(x))
+
+t_env = new.env(parent=baseenv())
+assign('h', h, t_env)
+environment(t) = t_env
+
+u_env = new.env(parent=baseenv())
+assign('g', g, u_env)
+assign('h', h, u_env)
+environment(u) = u_env
+
+f_env = new.env(parent=baseenv())
+assign('u', u, f_env)
+assign('h', h, f_env)
+assign('r', r, f_env)
+environment(f) = f_env
+
+a = function(x) x
+environment(a) = f_env
+
+test_that('mocked function is mocked at all depths across paths', {
+    stub_string = 'called stub!'
+    stub(f, 'h', stub_string, depth=4)
+    expect_equal(f(1), 'called stub!called stub!called stub!called stub!called stub!')
+})
+
+.a = function(x) h(x)
+test_that('mocks hidden functions', {
+    stub_string = 'called stub!'
+    stub(.a, 'h', stub_string, depth=4)
+    expect_equal(f(1), 'called stub!called stub!called stub!called stub!called stub!')
+})
diff --git a/vignettes/mocks-and-testthat.Rmd b/vignettes/mocks-and-testthat.Rmd
new file mode 100644
index 0000000..7609b58
--- /dev/null
+++ b/vignettes/mocks-and-testthat.Rmd
@@ -0,0 +1,252 @@
+---
+title: 'Mocks: Integrating with `testthat`'
+author: "Lukasz A. Bartnik"
+date: "`r Sys.Date()`"
+output: rmarkdown::html_vignette
+vignette: >
+  %\VignetteIndexEntry{Mocks: Integrating with testthat}
+  %\VignetteEngine{knitr::rmarkdown}
+  %\VignetteEncoding{UTF-8}
+---
+
+```{r include=FALSE}
+library(mockery)
+
+library(knitr)
+knitr::opts_chunk$set(collapse = TRUE, comment = "#>")
+```
+
+
+Mock object, which is a part of the `mockery` package, started as an
+extension to [testthat](github.com/hadley/testthat)'s `with_mock()`
+facility. Its main purpose was to simplify the replacement (mocking)
+of a given function by means of `with_mock` and the later
+verification of actual calls invoked on the replacing function.
+
+The `mockery` package which provides its own stubbing facility, the
+`stub()` function. Here, however, we will look only at how `mock()`
+can be used together with `with_mock()`.
+
+
+## Mocks
+
+### Creating a `mock` function
+
+Mocking is a well-known technique when it comes to unit-testing and in
+most languages there is some notion of a mock object. In R, however, the
+natural equivalent of a mock object is a mock _function_ - and this is
+exactly what a call to `mock()` will produce.
+
+```{r create_mock}
+m <- mock()
+```
+
+
+### Return values
+
+Let's look at arguments accepted by the `mock()` _factory_ function. The
+main is a list of values which will be returned upon subsequent calls to
+`m`.
+
+```{r return_values}
+m <- mock(1, 2, 3)
+m()
+m()
+m()
+```
+
+`mock()` can take also an expression which will be evaluated upon a call.
+
+```{r return_expression}
+x <- 1
+y <- 2
+m <- mock(x + y)
+m()
+```
+
+
+### Cycling through return values
+
+By default, if the total number of calls exceeds the number of defined
+return values, the _mock_ function will throw an exception. However, one
+can also choose to cycle through the list of retun values by setting the
+`cycle` argument of `mock()` to `TRUE`.
+
+```{r cycle_no, eval=FALSE}
+m <- mock(1, 2)
+m()
+#> [1] 1
+m()
+#> [1] 2
+m()
+#> Error: too many calls to mock object and cycle set to FALSE
+```
+
+```{r cycle_true}
+m <- mock(1, 2, cycle = TRUE)
+m()
+m()
+m()
+m()
+```
+
+
+If a return value is defined by an expression, this expression will be
+evaluated each time a cycle reaches its position.
+
+```{r cycle_expression}
+x <- 1
+y <- 2
+m <- mock(1, x + y, cycle = TRUE)
+
+m()
+m()
+```
+```{r cycle_expression_2nd}
+y <- 10
+m()
+m()
+```
+
+
+### Evaluating expression in an environment of choice
+
+Finally, one can specify the environment where the return expression is
+evaluated.
+
+```{r return_expression_env}
+x <- 1
+y <- 2
+e <- new.env()
+m <- mock(x + y, envir = e, cycle = TRUE)
+
+m()
+e$x <- 10
+m()
+```
+
+
+## Integration with `with_mock()`
+
+### Simple integration
+
+Using mock functions with `testthat`'s `with_mock()` is pretty
+straightforward.
+
+```{r with_mock, message=FALSE}
+library(testthat)
+
+m <- mock(1)
+f <- function (x) summary(x)
+with_mock(f = m, {
+  expect_equal(f(iris), 1)
+})
+```
+
+
+### Verifying the number of calls
+
+The `mockery` package comes with a few additional expectations which
+might turn out to be a very useful extension to `testthat`'s API. One
+can for example verify the number and signature of calls invoked on a
+mock function, as well as the values of arguments passed in those calls.
+
+First, let's make sure the mocked function is called exactly as many
+times as we expect. This can be done with `expect_called()`.
+
+```{r expect_called}
+m <- mock(1, 2)
+
+m()
+expect_called(m, 1)
+
+m()
+expect_called(m, 2)
+```
+
+And here is what happens when we get the number of calls wrong.
+
+```{r expect_called_error, eval=FALSE}
+expect_called(m, 1)
+#> Error: mock object has not been called 1 time.
+expect_called(m, 3)
+#> Error: mock object has not been called 3 times.
+```
+
+### Verify the call signature
+
+Another new expectation is `expect_call()` which compares the signature
+of the actual call as invoked on the mock function with the expected one.
+It takes as arguments: the mock function, the call number, expected call.
+
+```{r expect_call}
+m <- mock(1)
+with_mock(summary = m, {
+  summary(iris)
+})
+
+expect_call(m, 1, summary(iris))
+```
+
+And here is what happens if the call doesn't match.
+
+```{r call_doesnt_match, eval=FALSE}
+expect_call(m, 1, summary(x))
+#> Error: expected call summary(x) does not mach actual call summary(iris).
+```
+
+### Verify values of argument
+
+Finally, one can verify whether the actual values of arguments passed
+to the mock function match the expectation. Following the previous
+example of `summary(iris)` we can make sure that the `object` parameter
+passed to `m()` was actually the `iris` dataset.
+
+```{r expect_args}
+expect_args(m, 1, iris)
+```
+
+Here is what happens if the value turns out to be different.
+
+```{r expect_args_different, eval=FALSE}
+expect_args(m, 1, iris[-1, ])
+#> Error: arguments to call #1 not equal to expected arguments.
+#> Component 1: Attributes: < Component "row.names": Numeric: lengths (150, 149) differ >
+#> Component 1: Component 1: Numeric: lengths (150, 149) differ
+#> Component 1: Component 2: Numeric: lengths (150, 149) differ
+#> Component 1: Component 3: Numeric: lengths (150, 149) differ
+#> Component 1: Component 4: Numeric: lengths (150, 149) differ
+#> Component 1: Component 5: Lengths: 150, 149
+#> Component 1: Component 5: Lengths (150, 149) differ (string compare on first 149)
+#> Component 1: Component 5: 2 string mismatches
+#> expected argument list does not mach actual one.
+```
+
+If the call has been made with an explicit argument name the same has
+to appear in `expect_args()`.
+
+```{r expect_args_named}
+m <- mock(1)
+with_mock(summary = m, {
+  summary(object = iris)
+})
+
+expect_args(m, 1, object = iris)
+```
+
+Omitting the name results in an error.
+
+```{r expect_args_unnamed, eval=FALSE}
+expect_args(m, 1, iris)
+#> Error: arguments to call #1 not equal to expected arguments.
+#> names for target but not for current
+#> expected argument list does not mach actual one.
+```
+
+
+## Further reading
+
+More information can be found in examples presented in manual pages
+for `?mock` and `?expect_call`. Extensive information about testing
+in R can be found in the documentation for the
+[testthat](github.com/hadley/testthat) package.

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-med/r-cran-mockery.git



More information about the debian-med-commit mailing list