2017-05-10 2 views
2

Meine Anwendung verwendet die hyper Kiste, um einige Daten über HTTP zu liefern. Der Kern ist ein Handler-Funktion, wie folgt aus:Wie testet man eine Hyper-Server-HTTP-Handler-Funktion?

struct HttpHandler {} 

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

Hyper wird für jede HTTP-Anforderung diese Funktion aufrufen, die Requestreq und Responseres Variablen bereitstellt.

Ich möchte meine Einheit handle Funktion testen, so nenne ich die Funktion, ein Request und Response, und behaupten, vorausgesetzt, dass die Response verwendet worden, die erwarteten Daten zu senden („Hallo“).

Ich versuche, ein Request Objekt und ein Response Objekt in die handle Funktion zu instanziieren. Dafür sind mehrere Abhängigkeiten notwendig, die ich erstellen muss. Dazu kam ich ein Mock NetworkStream Implementierung bis:

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

jedoch Instanziieren die Request panics:

// 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(); 

Wo ist der Fehler in meinem Mock-Setup? Gibt es eine einfachere Möglichkeit, eine solche Handler-Funktion ohne so viel Code zu testen?

+0

Das sind keine guten impl von 'Read' und' Write'. .. Das könnte zu anderen Problemen führen. –

+1

Es ist hässlich, aber Sie könnten einfach die interne Implementierung von ['MockStream'] kopieren (https://github.com/hyperium/hyper/blob/0.10.x/src/mock.rs). – Shepmaster

Antwort

2

Der Request-Decoder erwartet eine HTTP-Anfrage, die vom Reader bereitgestellt wird.

Ihr Leser bietet ... nichts. Offensichtlich führt dies dazu, dass der Parser fehlschlägt.

+0

Ich verstehe das Problem, danke. Wenn ich jedoch 'let request = hyper :: server :: Request :: new (b" GET/HTTP/1.0 \ r \ n \ r \ n ", socket) .unwrap();' versuchen würde, würde sich der Compiler beschweren über nicht übereinstimmende Typen: erwarteter Typ '& mut hyper :: Puffer :: BufReader <& mut hyper :: net :: NetzwerkStream + 'statisch>' gefundener Typ '&' statisch [u8; 18] '. Ich werde versuchen, meinen Mock zu ändern, um gültige HTTP-Daten tatsächlich zurückzugeben. – pixelistik

+0

@pixelistik: Ja Entschuldigung. Es sieht so aus, als wäre es spezifischer, ich entferne den Vorschlag. –

1

Beantworten meiner eigenen Frage, aufbauend auf dem Eingang von @Matthieu und @Shempmaster.

Ich kopierte die MockStream Implementierung von der Hyper code, anstatt mein eigenes zu bauen.

diese verwenden, kann ich jetzt tun, was ich wollte: überprüfen, ob meine HTTP-Antwort die erwartete Laufzeit enthält:

#[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

Verwandte Themen