2017-05-10 36 views
2

我的應用程序使用hyper箱來通過HTTP提供一些數據。的核心是一個處理函數,如下所示:如何測試超級服務器HTTP處理函數?

struct HttpHandler {} 

impl hyper::server::Handler for HttpHandler { 
    fn handle(&self, req: hyper::server::Request, res: hyper::server::Response) { 
     res.send(b"Hello").unwrap(); 
    } 
} 

超將調用此函數爲每個HTTP請求,提供所述RequestreqResponseres變量。

我想單元測試我的handle功能,所以我打電話的功能,提供了一個RequestResponse,並且斷言Response已被用來發送預期數據(「你好」)。

我試圖實例化一個Request和一個Response對象,以傳入handle函數。爲此,需要創建幾個依賴關係。對於這一點,我最終實現模擬NetworkStream

mod tests { 
    use std::io; 
    use std::io::prelude::*; 
    use std::net::{IpAddr, Ipv4Addr, SocketAddr, SocketAddrV4}; 
    use std::time::Duration; 
    use hyper::server::Handler; 

    use super::*; 

    struct MockNetworkStream {} 

    impl Read for MockNetworkStream { 
     fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { 
      Ok(1) 
     } 
    } 

    impl Write for MockNetworkStream { 
     fn write(&mut self, buf: &[u8]) -> io::Result<usize> { 
      Ok(1) 
     } 

     fn flush(&mut self) -> io::Result<()> { 
      Ok(()) 
     } 
    } 

    impl hyper::net::NetworkStream for MockNetworkStream { 
     fn peer_addr(&mut self) -> Result<SocketAddr, io::Error> { 
      Ok(SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 8080))) 
     } 

     fn set_read_timeout(&self, dur: Option<Duration>) -> Result<(), io::Error> { 
      Ok(()) 
     } 

     fn set_write_timeout(&self, dur: Option<Duration>) -> Result<(), io::Error> { 
      Ok(()) 
     } 
    } 

    #[test] 
    fn test_handle() { 
     let handler = HttpHandler {}; 

     let mut request_mock_network_stream = MockNetworkStream {}; 

     let mut reader = hyper::buffer::BufReader::new(&mut request_mock_network_stream as 
                 &mut hyper::net::NetworkStream); 

     let socket = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8080); 

     // The following fails with 
     // 'tests::test_handle' panicked at 'called `Result::unwrap()` on an `Err` value: Header' 
     let request = hyper::server::Request::new(&mut reader, socket).unwrap(); 

     let mut headers = hyper::header::Headers::new(); 
     let mut response_mock_network_stream = MockNetworkStream {}; 
     let response = hyper::server::Response::new(&mut response_mock_network_stream, 
                &mut headers); 

     handler.handle(request, response); 

     // I would like to do some assert like this: 
     // assert_eq!(result, b"Hello"); 
    } 
} 

Full runnable playground example

然而,實例化Request恐慌:

// The following fails with 
// 'tests::test_handle' panicked at 'called `Result::unwrap()` on an `Err` value: Header' 
let request = hyper::server::Request::new(&mut reader, socket).unwrap(); 

哪裏是我的模擬設置錯誤了嗎?有沒有更簡單的方法來測試這樣的處理函數沒有太多的樣板代碼?

+0

這些都是Read'和'Write'的'沒有很好的實現了一套。這可能會導致其他問題。 –

+1

這很醜,但你可以複製['MockStream']的內部實現(https://github.com/hyperium/hyper/blob/0.10.x/src/mock.rs)。 – Shepmaster

回答

2

請求解碼器將期望找到由讀取器提供的HTTP請求。

您的讀者提供... 沒有什麼。顯然這會導致解析器失敗。

+0

我明白這個問題,謝謝。然而,如果我嘗試'let request = hyper :: server :: Request :: new(b「GET/HTTP/1.0 \ r \ n \ r \ n」,socket).unwrap();',編譯器會抱怨關於不匹配類型:預期類型'&mut hyper :: buffer :: BufReader <&mut hyper :: net :: NetworkStream +'static>'found type'&'static [u8; 18]'。我將嘗試修改我的模擬以實際返回有效的HTTP數據。 – pixelistik

+0

@pixelistik:對不起。它看起來比這更具體,我會刪除該建議。 –

1

回答我自己的問題,建立在@Matthieu和@Shepmaster的輸入上。

我複製了MockStream執行從Hyper code,而不是建立自己的。

利用這一點,我現在可以做什麼,我想:檢查是否我的HTTP響應包含預期的項:

#[test] 
fn test_handle() { 
    let handler = HttpHandler {}; 

    // Create a minimal HTTP request 
    let mut request_mock_network_stream = MockStream::with_input(b"GET/HTTP/1.0\r\n\r\n"); 

    let mut reader = hyper::buffer::BufReader::new(&mut request_mock_network_stream as 
                &mut hyper::net::NetworkStream); 

    let socket = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8080); 

    let request = hyper::server::Request::new(&mut reader, socket).unwrap(); 

    let mut headers = hyper::header::Headers::new(); 
    let mut response_mock_network_stream = MockStream::new(); 

    { 
     let response = hyper::server::Response::new(&mut response_mock_network_stream, 
                &mut headers); 

     handler.handle(request, response); 
    } 

    let result = str::from_utf8(&response_mock_network_stream.write).unwrap(); 

    assert!(result.contains("Hello")); 
} 

Full runnable code