#http #web-server #web #testing-http #http-client #spec #api

http_stub

实际Web服务器,测试整个栈。断言请求,并返回响应

4个版本

使用旧的Rust 2015

0.1.3 2016年6月17日
0.1.2 2016年4月22日
0.1.1 2016年4月22日
0.1.0 2016年4月21日

#40 in #testing-http


2 个crate使用

WTFPL 许可证

8KB
79

HttpStub

临时本地服务器,用于测试你的HTTP客户端代码。

实际Web服务器,
测试整个栈。
断言请求,
并发送响应回来。

它基于hyper,
因为它是最好的。
并且使用正则表达式断言,
而不仅仅是文本。

代码相当简单,
易于理解,
如果你想贡献,
请发送你的pull request。

安装

[dependencies]
http_stub = "0.1"

它看起来像什么?

请参阅文档中的实际示例 这里


lib.rs:

HttpStub: 临时本地服务器帮助你测试你的HTTP客户端代码。

可以轻松定义任意数量的stub服务器。对请求进行断言,并构建要发送的响应。

在GitHub上Fork

示例

extern crate http_stub;
extern crate hyper;

// Your client HTTP code will likely be using hyper too so
// this is the recommended way to use http_stub to avoid
// name clashing.
use self::http_stub as hs;
use self::http_stub::HttpStub;

// These modules are for the actual code we're writing and testing.
use std::io::Read;
use hyper::client::Client;
use hyper::status::StatusCode;

fn body_to_string<R: Read>(mut readable: R) -> String{
  let ref mut body = vec![];
  let _ = readable.read_to_end(body);
  String::from_utf8_lossy(body).into_owned()
}

fn main(){
  // Run an HttpStub server. It returns the URL where the server is listening,
  // for example: http://127.0.0.1:3001
  // It's fixed to listen on 127.0.0.1 and it will use up ports counting up from
  // port 3000, each new server will use the next port to make sure there are
  // no port conflicts. This does mean you should not be using those ports too.
  let server_one: String = HttpStub::run(|mut stub|{
    stub.got_body(r"foo=bar");
    stub.got_path("/a_post");
    stub.got_method(hs::Method::Post);
    stub.send_status(hs::StatusCode::NotFound);
    stub.send_header(hs::header::ContentType(
      hs::Mime(hs::TopLevel::Application, hs::SubLevel::Json, vec![])));

    // send_body should always be the last step. It writes the response body and sends it.
    // Rendering the 'response' field of the HttpStub unusable.
    stub.send_body("number one");
  });

  let server_two = HttpStub::run(|mut stub|{
    // Notice all search strings are actually used for creating a regex.
    // That's why we escape the '?' when matching for the path.
    stub.got_path(r"/a_get\?foo=bar");
    stub.got_method(hs::Method::Get);
    stub.send_status(hs::StatusCode::Ok);
    stub.send_header(hs::header::ContentType(
      hs::Mime(hs::TopLevel::Application, hs::SubLevel::Json, vec![])));
    stub.send_body("number two");
  });

  let client = Client::new();

  let response_one = client.post(&format!("{}/a_post", server_one))
    .body("foo=bar").send().unwrap();

  assert_eq!(response_one.status, StatusCode::NotFound);
  assert_eq!(body_to_string(response_one), "number one");

  let response_two = client.get(&format!("{}/a_get?foo=bar", server_two))
    .send().unwrap();

  assert_eq!(response_two.status, StatusCode::Ok);
  assert_eq!(body_to_string(response_two), "number two");
}

依赖项

~9MB
~197K SLoC