httpmock 0.4.1

HTTP mocking library for Rust
Documentation
<div align="center">
<h1>httpmock</h1>
</div>

<p align="center">HTTP mocking library for Rust.</p>
<div align="center">
    
[![Build Status](https://dev.azure.com/alexliesenfeld/httpmock/_apis/build/status/alexliesenfeld.httpmock?branchName=master)](https://dev.azure.com/alexliesenfeld/httpmock/_build/latest?definitionId=2&branchName=master)
[![codecov](https://codecov.io/gh/alexliesenfeld/httpmock/branch/master/graph/badge.svg)](https://codecov.io/gh/alexliesenfeld/httpmock)
[![crates.io](https://img.shields.io/crates/d/httpmock.svg)](https://crates.io/crates/httpmock)
[![Docker](https://img.shields.io/docker/cloud/build/alexliesenfeld/httpmock)](https://hub.docker.com/r/alexliesenfeld/httpmock)
[![License](https://img.shields.io/github/license/alexliesenfeld/httpmock.svg)](LICENSE)
	
</div>

<p align="center">
    <a href="https://docs.rs/httpmock/">Documentation</a>
    ·
    <a href="https://crates.io/crates/httpmock">Crate</a>
    ·
    <a href="https://github.com/alexliesenfeld/httpmock/issues">Report Bug</a>
    ·
    <a href="https://github.com/alexliesenfeld/httpmock/issues">Request Feature</a>
</p>

## Features

* Provides a full-blown HTTP mock server with HTTP/1 and HTTP/2 support.
* A fully asynchronous core with synchronous and asynchronous APIs.
* Compatible with all major asynchronous executors and runtimes.
* Built-in request matchers with support for custom request matchers.
* Parallel test execution by default.
* A standalone mode with an accompanying [Docker image](https://hub.docker.com/r/alexliesenfeld/httpmock).

## Getting Started
Add `httpmock` to `Cargo.toml`:

```toml
[dev-dependencies]
httpmock = "0.4.0"
```

You can then use `httpmock` in your tests like shown in the example below:
```rust
extern crate httpmock;

use httpmock::Method::{GET};
use httpmock::{Mock, MockServer, MockServerRequest, Regex};

#[test]
fn example_test() {
    // Arrange: Create a mock on a local mock server 
    let mock_server = MockServer::start();

    let search_mock = Mock::new()
        .expect_method(GET)         
        .expect_path("/search")
        .return_status(200)
        .create_on(&mock_server);

    // Act: Send an HTTP request to the mock server (simulates your software)
    let url = format!("http://{}/search", mock_server.address());
    let response = isahc::get(&url).unwrap();

    // Assert: Ensure there was a response from the mock server
    assert_eq!(response.status(), 200);
    assert_eq!(search_mock.times_called(), 1);
}
```

## API Usage

Each test usually creates its own local `MockServer` using `MockServer::start()`. This creates a lightweight HTTP
server that runs on its own port. This way tests do not conflict with each other.

You can use the `Mock`  structure to specify and create mocks on the mock server. It provides you all supported mocking 
functionality.

### Request Matching and Responses
Other than many other libraries `httpmock` does not require you to learn a DSL-like API to
specify mock behaviour. Instead, `httpmock` provides you a fluent builder API that
clearly separates request matching and response attributes by using the following naming scheme:

- All `Mock` methods that start with `expect` in their name set a requirement
for HTTP requests (e.g. `Mock::expect_method`, `Mock::expect_path`, or `Mock::expect_body`).
- All `Mock` methods that start with `return` in their name define what the
mock server will return in response to an HTTP request that matched all mock requirements (e.g.
`Mock::return_status`, `Mock::return_body`, etc.).

With this naming scheme users can benefit from IDE autocompletion to find request matchers and
response attributes mostly without even looking into documentation.

If a request does not match at least one mock, the server will respond with
an error message and HTTP status code 404 (Not Found).

### Sync / Async

The internal implementation of `httpmock` is fully asynchronous. It provides you a synchronous and an asynchronous API 
though. If you want to schedule awaiting operations manually, then you can use the `async` variants that exist for every 
potentially blocking operation. For example, there is `MockServer::start_async` as an asynchronous 
counterpart to `MockServer::start` and `Mock::create_on_async` for `Mock::create_on`. 

## Parallelism
To balance execution speed and resource consumption, `MockServer`s are kept in a server pool internally. This allows to run multiple tests in parallel without overwhelming the executing machine by creating too many HTTP servers. A test will be blocked if it tries to use a `MockServer` (e.g. by calling `MockServer::new()`) while the server pool is empty (i.e. all servers are occupied by other tests). To avoid TCP port binding issues, `MockServers` are never recreated but recycled/resetted. The pool is filled on demand up to a predefined maximum number of 25 servers. You can change this number by setting the environment variable `HTTPMOCK_MAX_SERVERS`. 


## Examples
Fore more examples, please refer to
[this crates test directory](https://github.com/alexliesenfeld/httpmock/blob/master/tests/integration_tests.rs ).

## Debugging
`httpmock` logs against the `log` crate. For example, if you use the `env_logger` backend, you can activate debug logging by setting the `RUST_LOG` environment variable to `httpmock=debug`.

## Standalone Mode
You can use `httpmock` to run a standalone mock server that is available to multiple applications. This can be useful if you are running integration tests that involve both, real and mocked applications. 

### Docker
Altough you can build the mock server in standalone mode yourself, it is easiest to use the Docker image from the accompanying [Docker image](https://hub.docker.com/r/alexliesenfeld/httpmock). Please refer to the documentation on Docker repository. 

### API Usage
To be able to use a standalone server from your tests, you need to change how an instance of the `MockServer` structure is created. Instead of using `MockServer::new()`, you need to connect to a remote server by using one of the `connect` methods (such as `MockServer::connect("localhost:5000")` or `MockServer::connect_from_env()`). Therefore, tests that use a local mock server do only differ in one line of code from tests that use a remote server. Otherwise, both variants are identical. 

```Rust
#[test]
fn simple_test() {
    // Arrange: Create a mock on a test local mock server 
    let mock_server = MockServer::connect("some-host:5000");

    let search_mock = Mock::new()
        .expect_method(GET)         
        .expect_path("/search")
        .return_status(200)
        .create_on(&mock_server);

    // Act: Send an HTTP request to the mock server (simulates your software)
    let url = format!("http://{}/search", mock_server.address())).unwrap();
    let response = http_get(&url).unwrap();

    // Assert: Ensure there was a response from the mock server
    assert_eq!(response.status(), 200);
    assert_eq!(search_mock.times_called(), 1);
}
```

### Parallelism
Tests that use a remote mock server are executed sequentially by default. This is in contrast to tests that use a local mock server. Sequential execution is achieved by blocking all tests from further execution whenever a test requires to connect to a busy mock server. 

### Limitations
At this time, it is not possible to use custom request matchers in combination with remote
mock servers. It is planned to add this functionality in future though.

### Examples
Fore more examples on how to use a remote server, please refer to
[this crates test directory](https://github.com/alexliesenfeld/httpmock/blob/master/tests/standalone_tests.rs ).

## License
`httpmock` is free software: you can redistribute it and/or modify it under the terms of the MIT Public License.
 
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied 
warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MIT Public License for more details.