Info
This post is auto-generated from RSS feed The Rust Programming Language Forum - Latest topics. Source: Mocking tokio, hyper and reqwest without using trait or changing production code by using injectorpp
Hi,
We have recently added tests in injectorpp to demonstrate how to fake tokio
, hyper
and reqwest
requests without using trait or changing production code. See tokio.rs, hyper.rs and reqwest.rs
Since reqwest
uses hyper
, hyper
is built on top of tokio
, The basic steps are all the same:
TcpStream
.TcpSocket::connect
to return the mock TcpStream
.Uri::scheme_str
to make it always return http
to bypass all tls validation.We can take a breakdown for reqwest.rs.
TcpStream
TcpStream
cannot be directly created as it does not provide public constructor. make_tcp_with_json_response is an example to write the expected contents to a temporary listen port to get a TcpStream
object.
Our goal is sending to any host should get the mock response we set even if that host does not exist. So we need to fake the to_socket_addr
function:
type ToSocketAddrsFn =
fn(&(&'static str, u16)) -> std::io::Result<std::vec::IntoIter<SocketAddr>>;
let fn_ptr: ToSocketAddrsFn = <(&'static str, u16) as ToSocketAddrs>::to_socket_addrs;
unsafe {
injector
.when_called_unchecked(injectorpp::func_unchecked!(fn_ptr))
.will_execute_raw_unchecked(injectorpp::closure_unchecked!(
|_addr: &(&str, u16)| -> std::io::Result<std::vec::IntoIter<SocketAddr>> {
Ok(vec![SocketAddr::from(([127, 0, 0, 1], 0))].into_iter())
},
fn(&(&str, u16)) -> std::io::Result<std::vec::IntoIter<SocketAddr>>
));
}
TcpSocket::connect
to return the mock TcpStream
Now it's time to fake the TcpSocket::connect
to return the contents we expect in the test:
let temp_socket = TcpSocket::new_v4().expect("Failed to create temp socket");
let temp_addr = "127.0.0.1:0".parse().unwrap();
// Mock TcpSocket::connect method
injector
.when_called_async(injectorpp::async_func!(
temp_socket.connect(temp_addr),
std::io::Result<TcpStream>
))
.will_return_async(injectorpp::async_return! {
make_tcp_with_json_response(),
std::io::Result<TcpStream>
});
Uri::scheme_str
to make it always return http
to bypass all tls validationhttps
needs additional tls validation and it's one of the tough challenges for testing the code that sends requests. But now it's easy to bypass it by faking Uri::scheme_str
:
// Force using http to bypass tls validation
injector
.when_called(injectorpp::func!(fn (Uri::scheme_str)(&Uri) -> Option<&str>))
.will_execute(injectorpp::fake!(
func_type: fn(_uri: &Uri) -> Option<&str>,
returns: Some("http")
));
Now sending any https request to any host will return the contents you set.
Hope this can help you solving the pain point for writing unit tests when using above libraries.
Please leave your suggestions and questions, we'd like to understand your pain point and to see if injectorpp can help. We're also considering wrapping an utility module to simplify some steps when faking these libraries. Please do let us know your thoughts. Thanks!
1 post - 1 participant
🏷️ rust_feed