Frequently Asked Questions

Where are my mocks recorded?

By default, the destination path for capture_requests() is relative to the current working directory of the process. This matches the behavior of with_mock_api(), which looks for files relative to its directory, which typically is tests/testthat/.

If you’re running capture_requests within a test suite in an installed package, or if you’re running interactively from a different directory, the working directory may not be the same as your code repository. If you aren’t sure where the files are going, set options(httptest.verbose=TRUE), and it will message the absolute path of the files as it writes them.

To change where files are being written or read from, use .mockPaths() (like base::.libPaths()) to specify a different directory.

How do I fix “non-portable file paths”?

If you see this error in R CMD build or R CMD check, it means that there are file paths are longer than 100 characters, which can sometimes happen when you record requests. httptest preserves the URL structure of mocks in file paths to improve the readability and maintainability of your tests, as well as to make visible the properties of your API. Indeed, the file-system tree view of the mock files gives a visual representation of your API. This value comes with a tradeoff: sometimes URLs can be long, and R doesn’t like that.

Depending on how long your URLs are, there are a few ways to save on characters without compromising readability of your code and tests.

A big way to cut long file paths is by using a request preprocessor: a function that alters the content of your ‘httr’ request before mapping it to a mock file. For example, if all of your API endpoints sit beneath https://language.googleapis.com/v1/, you could set a request preprocessor like:

set_requester(function (request) {
  gsub_request(request, "https\\://language.googleapis.com/v1/", "api/")
})

and then all mocked requests would look for a path starting with “api/” rather than “language.googleapis.com/v1/”, saving you (in this case) 23 characters.

You can also provide this function in inst/httptest/request.R, and any time your package is loaded (as when you run tests or build vignettes), this function will be called automatically. See vignette("redacting") for more.

You may also be able to economize on other parts of the file paths. If you’ve recorded requests and your file paths contain long ids like “1495480537a3c1bf58486b7e544ce83d”, depending on how you access the API in your code, you may be able to simply replace that id with something shorter, like “1”. The mocks are just files, disconnected from a real server and API, so you can rename them and munge them as needed.

Finally, if you have your tests inside a tests/testthat/ directory, and your fixture files inside that, you can save 9 characters by moving the fixtures up to tests/ and setting .mockPaths("../").

How do I switch between mocking and real requests?

httptest does not intend that every request in your test suite is something that could be run against a live server. There are practical reasons why you should be able to see, modify, and maintain test fixtures, rather than re-record them every time you make a change. Among the considerations:

That said, it can be worthwhile to have a subset of tests that can be run against a live API so that you can detect and respond to API changes. One option is to set up some tests with the with_mock_dir() context instead of with_mock_api(). For example:

with_mock_dir("httpbin-get", {
  a <- GET("https://httpbin.org/get")
  print(a)
})

The first time you run the code, it will create the directory tests/testthat/httpbin-get, and create mock files under it. The next times you run it, it will use the mock files in tests/testthat/httpbin-get. To re-record, simply delete the directory.

Another option is to have a secondary integration test suite in your code repository, a directory outside of the standard R package directories and included in .Rbuildignore so that it doesn’t get packaged. You could run this locally with testthat::test_dir(), and you could run it on continuous integration builds by replacing the tests/testthat directory with the alternate test directory.