httpmock
HTTP 模拟库,为 Rust 语言设计。
文档:Documentation[1] 包:Crate[2] 报告错误:Report Bug[3] 功能请求:Request Feature[4] 更新日志:Changelog[5] 支持项目:Support this Project[6]
特性
简单、表达性强、流畅的 API。 内置多种辅助工具,便于请求匹配(正则表达式、JSON、序列化、cookies 等)。 并行测试执行。 可扩展的请求匹配。 完全异步的核心,提供同步和异步 API。 高级验证和调试支持(包括实际和预期 HTTP 请求值之间的差异生成)。 故障和网络延迟模拟。 支持正则表达式匹配、JSON、序列化、cookies 等。 独立模式,附带Docker 镜像[7]。 支持使用 YAML 文件配置模拟[8]。
开始使用
在Cargo.toml
中添加httpmock
:
[dev-dependencies]
httpmock = "0.7.0"
然后可以按照以下方式使用httpmock
:
use httpmock::prelude::*;
// 启动轻量级模拟服务器。
let server = MockServer::start();
// 在服务器上创建一个模拟。
let mock = server.mock(|when, then| {
when.method(GET)
.path("/translate")
.query_param("word", "hello");
then.status(200)
.header("content-type", "text/html; charset=UTF-8")
.body("Привет");
});
// 向模拟服务器发送HTTP请求。这模拟了您的代码。
let response = isahc::get(server.url("/translate?word=hello")).unwrap();
// 确保指定的模拟被调用了恰好一次(或者以详细的错误描述失败)。
mock.assert();
// 确保模拟服务器的响应如指定的那样。
assert_eq!(response.status(), 200);
上述示例将启动一个轻量级的 HTTP 模拟服务器,并配置它响应所有GET
请求到路径/translate
,查询参数为word=hello
。相应的 HTTP 响应将包含文本体Привет
。
如果请求失败,httpmock
将显示包括预期和实际 HTTP 请求之间的差异的详细错误描述:
详细文档
Crate httpmock
开始使用
在 Cargo.toml
中添加 httpmock
:
[dev-dependencies]
httpmock = "0.7.0-rc.1"
使用示例:
use httpmock::prelude::*;
// 启动一个轻量级模拟服务器。
let server = MockServer::start();
// 在服务器上创建一个模拟。
let hello_mock = server.mock(|when, then| {
when.method(GET)
.path("/translate")
.query_param("word", "hello");
then.status(200)
.header("content-type", "text/html")
.body("ohi");
});
使用方法
首先需要启动一个模拟服务器,通过调用 MockServer::start
。这将在后台启动一个轻量级 HTTP 模拟服务器,并等待服务器准备好接受请求。
然后,可以使用 MockServer::mock
方法在服务器上创建一个 Mock
对象。该方法期望一个闭包,包含两个参数,我们称之为 when
和 then
参数:
when
参数是When
类型,包含所有请求特征。模拟服务器只会响应符合所有标准的 HTTP 请求。否则,将返回 HTTP 状态码 404 和错误消息。then
参数是Then
类型,包含模拟服务器将响应的所有值。
同步 / 异步
httpmock
的内部实现完全异步。尽管如此,它提供了同步和异步 API。如果你想手动安排等待操作,可以使用每个可能阻塞操作的异步变体。例如,MockServer::start_async
是 MockServer::start
的异步对应版本。你可以在整个库中找到类似的方法。
并行性
为了平衡执行速度和资源消耗,模拟服务器在内部服务器池中保持。这允许在不通过创建太多 HTTP 服务器而压垮执行机器的情况下并行运行测试。如果测试尝试使用 MockServer
(例如,通过调用 MockServer::start
)而服务器池为空(即所有服务器都被其他测试占用),则测试将被阻塞。
// 向模拟服务器发送 HTTP 请求。这模拟了你的代码。
let response = isahc::get(server.url("/translate?word=hello")).unwrap();
// 确保指定的模拟被调用了恰好一次(或者失败)。
hello_mock.assert();
// 确保模拟服务器按指定响应。
assert_eq!(response.status(), 200);
模拟服务器永远不会被重新创建,而是被回收/重置。池按需填充,最多可包含 25 个服务器。你可以使用环境变量 HTTPMOCK_MAX_SERVERS
覆盖此数字。
调试
httpmock
使用 log
crate 进行日志记录。这允许你看到包含有关 httpmock
行为的详细信息的详细日志输出。你可以使用这些日志输出来调查问题,例如找出为什么一个请求不匹配模拟定义。
最有用的日志级别是 debug
,但你也可以降低到 trace
以查看更多信息。
注意:要能够看到日志输出,你需要在启动测试执行时添加 --nocapture
参数!
提示:如果你使用 env_logger
后端,你需要设置 RUST_LOG
环境变量为 httpmock=debug
。
API 替代方案
这个库提供了两个功能上可互换的 DSL API,允许你在服务器上创建模拟。你可以选择你最喜欢的一个,或者两者并行使用。为了保持一致的外观,建议坚持使用其中之一。
When/Then API
这是 httpmock
的默认 API。它简洁易读。主要目标是将库带来的开销减少到最低。它与格式化工具(如 rustfmt,即 cargo fmt)很好地配合工作,并且可以完全受益于 IDE 支持。
示例:
let server = httpmock::MockServer::start();
let greeting_mock = server.mock(|when, then| {
when.path("/hi");
then.status(200);
});
let response = isahc::get(server.url("/hi")).unwrap();
greeting_mock.assert();
注意 when
和 then
是变量。这允许你将它们重命名为你更喜欢的名称(例如 expect/respond_with
)。
这个 API 的相关元素是 MockServer::mock
,When
和 Then
。
示例可以在该 crate 的 Git 仓库的测试目录中找到。
独立模式
你可以使用 httpmock
运行一个独立的模拟服务器,它在一个单独的进程中运行。这允许它对多个应用程序可用,不仅仅在你的单元和集成测试中。这在你想在系统(甚至端到端)测试中使用 httpmock
,需要模拟服务时非常有用。有了这个功能,httpmock
是一个在开发生命周期的所有阶段都非常有用的通用 HTTP 模拟工具。
使用独立模拟服务器
尽管你可以自己构建独立模式的模拟服务器,但使用附带的 Docker 镜像是最简单的。
为了能够在测试中使用独立服务器,你需要改变创建 MockServer
实例的方式。不是使用 MockServer::start
,而是需要使用其中一个连接方法(如 MockServer::connect
或 MockServer::connect_from_env
)连接到远程服务器。注意:这些仅在启用远程特性时可用。
use httpmock::prelude::*;
use isahc::get;
#[test]
fn simple_test() {
// Arrange
let server = MockServer::connect("some-host:5000");
let hello_mock = server.mock(|when, then| {
when.path("/hello/standalone");
then.status(200);
});
// Act
let response = get(server.url("/hello/standalone")).unwrap();
// Assert
hello_mock.assert();
assert_eq!(response.status(), 200);
}
独立并行性
为了防止与其他测试的干扰,测试函数被迫顺序使用独立模拟服务器。这意味着当连接到远程服务器时,测试函数可能会被阻塞,直到服务器再次空闲。这与使用本地模拟服务器的测试形成对比。
独立模式的限制
目前,无法将自定义请求匹配器与独立模拟服务器结合使用(见 When::matches
或 Mock::expect_match
)。
使用 YAML 模拟定义文件的独立模式
独立服务器还可以在启动时从 YAML 文件中读取模拟定义,并在服务器再次关闭之前提供模拟端点。这些静态模拟在运行时不能被删除(即使是使用模拟服务器的基于 Rust 的测试),并且在模拟服务器的整个正常运行时间内存在。
定义文件遵循你在常规 Rust 测试中也会使用的 httpmock
标准 API。可以在 httpmock
Github 仓库的测试目录中找到示例模拟定义文件。
你可以按以下方式启动支持静态模拟的模拟服务器:
如果你使用该创建仓库或 Dockerhub 中的 Docker 镜像,你只需要将包含所有模拟规范文件的卷挂载到容器内的 /mocks
目录。如果你从源代码构建 httpmock
并使用二进制文件,那么你可以传递包含所有模拟规范文件的目录路径,使用 --static-mock-dir
参数。示例:httpmock --expose --static-mock-dir=/mocks
。
示例
您可以在`httpmock`测试目录[9]中找到示例。参考文档[10] 也包含了许多示例。还有一个在线教程[11]。
Documentation: https://docs.rs/httpmock/
[2]Crate: https://crates.io/crates/httpmock
[3]Report Bug: https://github.com/alexliesenfeld/httpmock/issues
[4]Request Feature: https://github.com/alexliesenfeld/httpmock/issues
[5]Changelog: https://github.com/alexliesenfeld/httpmock/blob/master/CHANGELOG.md
[6]Support this Project: https://github.com/sponsors/alexliesenfeld
[7]Docker 镜像: https://hub.docker.com/r/alexliesenfeld/httpmock
[8]配置模拟: https://github.com/alexliesenfeld/httpmock/tree/master#file-based-mock-specification
[9]httpmock
测试目录: https://github.com/alexliesenfeld/httpmock/blob/master/tests/
参考文档: https://docs.rs/httpmock/
[11]在线教程: https://alexliesenfeld.com/mocking-http-services-in-rust