Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/ropensci/webmockr

Stub and set expectations on HTTP requests
https://github.com/ropensci/webmockr

fakeweb http http-mock http-mocking mock r r-package rstats tdd testing testing-tools

Last synced: 11 days ago
JSON representation

Stub and set expectations on HTTP requests

Awesome Lists containing this project

README

        

webmockr
========

```{r echo=FALSE}
knitr::opts_chunk$set(
comment = "#>",
collapse = TRUE,
warning = FALSE
)
```

[![cran checks](https://badges.cranchecks.info/worst/webmockr.svg)](https://cloud.r-project.org/web/checks/check_results_webmockr.html)
[![Project Status: Active - The project has reached a stable, usable state and is being actively developed.](https://www.repostatus.org/badges/latest/active.svg)](https://www.repostatus.org/#active)
[![R-CMD-check](https://github.com/ropensci/webmockr/workflows/R-CMD-check/badge.svg)](https://github.com/ropensci/webmockr/actions/)
[![codecov](https://codecov.io/gh/ropensci/webmockr/branch/main/graph/badge.svg?token=1zWlEQbaEh)](https://codecov.io/gh/ropensci/webmockr)
[![rstudio mirror downloads](https://cranlogs.r-pkg.org/badges/webmockr)](https://github.com/r-hub/cranlogs.app)
[![cran version](https://www.r-pkg.org/badges/version/webmockr)](https://cran.r-project.org/package=webmockr)

R library for stubbing and setting expectations on HTTP requests.

Port of the Ruby gem [webmock](https://github.com/bblimke/webmock)

How it works in detail

```{r details, child="details.html"}
```

## Features

* Stubbing HTTP requests at low http client lib level
* Setting and verifying expectations on HTTP requests
* Matching requests based on method, URI, headers and body
* Support for `testthat` via [vcr][]
* Can be used for testing or outside of a testing context
* Supports async http request mocking with `crul` only

## Supported HTTP libraries

* [crul](https://github.com/ropensci/crul)
* [httr](https://github.com/r-lib/httr)
* [httr2](https://github.com/r-lib/httr2)

## Install

from cran

```{r eval=FALSE}
install.packages("webmockr")
```

Dev version

```{r eval=FALSE}
# install.packages("pak")
pak::pak("ropensci/webmockr")
```

```{r}
library(webmockr)
```

## Enable webmockr

```{r}
webmockr::enable()
```

## Inside a test framework

```{r}
library(crul)
library(testthat)

# make a stub
stub_request("get", "https://httpbin.org/get") %>%
to_return(body = "success!", status = 200)

# check that it's in the stub registry
stub_registry()

# make the request
z <- crul::HttpClient$new(url = "https://httpbin.org")$get("get")

# run tests (nothing returned means it passed)
expect_is(z, "HttpResponse")
expect_equal(z$status_code, 200)
expect_equal(z$parse("UTF-8"), "success!")
```

```{r echo=FALSE}
stub_registry_clear()
```

## Outside a test framework

```{r}
library(crul)
```

### Stubbed request based on uri only and with the default response

```{r}
stub_request("get", "https://httpbin.org/get")
```

```{r}
x <- HttpClient$new(url = "https://httpbin.org")
x$get('get')
```

set return objects

```{r}
stub_request("get", "https://httpbin.org/get") %>%
wi_th(
query = list(hello = "world")) %>%
to_return(status = 418)
```

```{r}
x$get('get', query = list(hello = "world"))
```

### Stubbing requests based on method, uri and query params

```{r}
stub_request("get", "https://httpbin.org/get") %>%
wi_th(query = list(hello = "world"),
headers = list('User-Agent' = 'libcurl/7.51.0 r-curl/2.6 crul/0.3.6',
'Accept-Encoding' = "gzip, deflate"))
```

```{r}
stub_registry()
```

```{r}
x <- HttpClient$new(url = "https://httpbin.org")
x$get('get', query = list(hello = "world"))
```

### Stubbing requests and set expectation of a timeout

```{r error=TRUE}
stub_request("post", "https://httpbin.org/post") %>% to_timeout()
x <- HttpClient$new(url = "https://httpbin.org")
x$post('post')
```

### Stubbing requests and set HTTP error expectation

```{r error=TRUE}
library(fauxpas)
stub_request("get", "https://httpbin.org/get?a=b") %>% to_raise(HTTPBadRequest)
x <- HttpClient$new(url = "https://httpbin.org")
x$get('get', query = list(a = "b"))
```

## httr integration

```{r}
library(webmockr)
library(httr)

# turn on httr mocking
httr_mock()
```

```{r eval=FALSE}
# no stub found
GET("https://httpbin.org/get")
#> Error: Real HTTP connections are disabled.
#> Unregistered request:
#> GET https://httpbin.org/get with headers {Accept: application/json, text/xml, application/xml, */*}
#>
#> You can stub this request with the following snippet:
#>
#> stub_request('get', uri = 'https://httpbin.org/get') %>%
#> wi_th(
#> headers = list('Accept' = 'application/json, text/xml, application/xml, */*')
#> )
#> ============================================================
```

make a stub

```{r}
stub_request('get', uri = 'https://httpbin.org/get') %>%
wi_th(
headers = list('Accept' = 'application/json, text/xml, application/xml, */*')
) %>%
to_return(status = 418, body = "I'm a teapot!!!", headers = list(im_a = "teapot"))
```

now returns mocked response

```{r eval=FALSE}
(res <- GET("https://httpbin.org/get"))
res$status_code
#> [1] 418
res$headers
#> $im_a
#> [1] "teapot"
```

## httr2 integration

```{r message=FALSE}
library(webmockr)
library(httr2)

# turn on httr2 mocking
enable()
```

```{r eval=FALSE}
# no stub found
req <- request("https://hb.opencpu.org/get")
req_perform(req)
#> Error: Real HTTP connections are disabled.
#> Unregistered request:
#> GET https://hb.opencpu.org/get
#>
#> You can stub this request with the following snippet:
#>
#> stub_request('get', uri = 'https://hb.opencpu.org/get')
#> ============================================================
```

make a stub

```{r}
stub_request('get', uri = 'https://hb.opencpu.org/get') %>%
to_return(status = 418, body = "I'm a teapot!!!", headers = list(im_a = "teapot"))
```

now returns mocked response

```{r eval=FALSE}
req <- request("https://hb.opencpu.org/get")
res <- req_perform(req)
res
res$status_code
#> [1] 418
res$headers
#>
#> im_a: teapot
```

## Writing to disk

Write to a file before mocked request

```{r echo=FALSE}
stub_registry_clear()
request_registry_clear()
```

```{r}
## make a temp file
f <- tempfile(fileext = ".json")
## write something to the file
cat("{\"hello\":\"world\"}\n", file = f)
readLines(f)
## make the stub
invisible(stub_request("get", "https://httpbin.org/get") %>%
to_return(body = file(f)))
## make a request
out <- HttpClient$new("https://httpbin.org/get")$get(disk = f)
readLines(file(f))
```

OR - you can use `mock_file()` to have `webmockr` handle file and contents

```{r}
g <- tempfile(fileext = ".json")
## make the stub
invisible(stub_request("get", "https://httpbin.org/get") %>%
to_return(body = mock_file(g, "{\"hello\":\"mars\"}\n")))
## make a request
out <- crul::HttpClient$new("https://httpbin.org/get")$get(disk = g)
readLines(out$content)
```

Writing to disk is supported in `crul`, `httr`, and `httr2`

## Many requests in a row

e.g., many redirects, then a final successful request

```{r eval=FALSE}
webmockr::enable()
library(crul)
library(fauxpas)

z <- stub_request("get", "https://httpbin.org/get")
to_return(z, status = 200, body = "foobar", headers = list(a = 5))
to_return(z, status = 200, body = "bears", headers = list(b = 6))
to_raise(z, HTTPBadRequest)
z

con <- crul::HttpClient$new(url = "https://httpbin.org")
# the first to_return()
first <- con$get("get")
first
first$parse("UTF-8")
# the second to_return()
second <- con$get("get")
second
second$parse("UTF-8")
# the third to_return() - fails as specified
third <- con$get("get")
```

Note that subsequent requests past the number of responses given with `to_return()`/etc.
simply gives the last response you specified. Although if you set a `to_timeout` or
`to_raise` this feature won't happen since you fail out.

## Contributors

* [Scott Chamberlain](https://github.com/sckott)
* [Aaron Wolen](https://github.com/aaronwolen)

## Meta

* Please [report any issues or bugs](https://github.com/ropensci/webmockr/issues).
* License: MIT
* Get citation information for `webmockr` in R doing `citation(package = 'webmockr')`
* Please note that this package is released with a [Contributor Code of Conduct](https://ropensci.org/code-of-conduct/). By contributing to this project, you agree to abide by its terms.

[vcr]: https://github.com/ropensci/vcr