TCP 서버 테스트하기
handle_connection 함수를 테스트해 봅시다.
먼저, 테스트에 사용될 TcpStream이 필요합니다. 단대단이나 통합 테스트에서는
코드 테스트를 위해 실제 TCP 연결이 필요할 수도 있습니다. 실제 TCP 연결을
사용하여 테스트하는 방법 중 하나는 localhost의 0번 포트에서 리스닝하는
것입니다. 0번 포트는 유효한 유닉스 포트가 아니지만 테스트 목적으로는 작동합니다.
운영체제가 열린 TCP 포트를 하나 골라 줄 것입니다.
하지만, 아래 예제에서는 연결 핸들러에 대한 유닛 테스트를 작성하여, 각각의 입력에
맞는 올바른 응답이 반환되었는지 확인할 것입니다. 유닛 테스트를 격리되고
결정론적이게 만들기 위해,  TcpStream을 모조품으로 대체할 것입니다.
먼저, 테스트하기 쉽게 handle_connection의 시그니처를 바꿀
것입니다. 사실 handle_connection는 async_std::net::TcpStream이 꼭 필요한
것은 아닙니다. async_std::io::Read, async_std::io::Write, 그리고 marker::Unpin을 구현하는
어떤 구조체도 가능합니다. 이 내용을 반영하여 타입 시그니처를 바꾸면 모조품을
테스트 용으로 넘겨 줄 수 있게 됩니다.
use std::marker::Unpin;
use async_std::io::{Read, Write};
async fn handle_connection(mut stream: impl Read + Write + Unpin) {
이 트레잇 세 개를 구현하는 TcpStream 모조품을 만들어 봅시다.
먼저, poll_read 메소드 한 개만 있는 Read 트레잇을 구현합시다.
TcpStream 모조품은 읽기 버퍼로 복사되는 어떤 데이터를 가지고 있을 것이고,
복사가 끝나면 poll_read는 읽기가 끝났음을 알리는 Poll::Ready를 반환할 것입니다.
    use super::*;
    use futures::io::Error;
    use futures::task::{Context, Poll};
    use std::cmp::min;
    use std::pin::Pin;
    struct MockTcpStream {
        read_data: Vec<u8>,
        write_data: Vec<u8>,
    }
    impl Read for MockTcpStream {
        fn poll_read(
            self: Pin<&mut Self>,
            _: &mut Context,
            buf: &mut [u8],
        ) -> Poll<Result<usize, Error>> {
            let size: usize = min(self.read_data.len(), buf.len());
            buf[..size].copy_from_slice(&self.read_data[..size]);
            Poll::Ready(Ok(size))
        }
    }
poll_write, poll_flush, 그리고 poll_close라는 세 개의 메소드를 작성해야
할지라도 Write 구현은 매우 간단합니다.
poll_write는 모든 입력 데이터를 TcpStream 모조품으로 복사하고, 완성되면
Poll::Ready를 반환할 것입니다. TcpStream 모조품을 플러싱하거나 닫기 위한
별도 작업이 필요 없기 때문에 poll_flush와 poll_close는 그냥 Poll::Ready를
반환하면 됩니다.
    impl Write for MockTcpStream {
        fn poll_write(
            mut self: Pin<&mut Self>,
            _: &mut Context,
            buf: &[u8],
        ) -> Poll<Result<usize, Error>> {
            self.write_data = Vec::from(buf);
            Poll::Ready(Ok(buf.len()))
        }
        fn poll_flush(self: Pin<&mut Self>, _: &mut Context) -> Poll<Result<(), Error>> {
            Poll::Ready(Ok(()))
        }
        fn poll_close(self: Pin<&mut Self>, _: &mut Context) -> Poll<Result<(), Error>> {
            Poll::Ready(Ok(()))
        }
    }
마지막으로, TcpStream 모조품은 메모리 상 위치가 안전하게 움직일 수 있다고
알리는 Unpin을 구현해야 합니다.
Unpin에 대한 자세한 정보는 고정하기를 참고하세요.
    use std::marker::Unpin;
    impl Unpin for MockTcpStream {}
이제 handle_connection 함수를 테스트할 준비가 되었습니다.
MockTcpStream이 임의의 초기 데이터를 가지도록 설정한 다음,
#[async_std::main]의 사용과 유사하게 #[async_std::test] 속성을 이용하여
handle_connection을 실행할 수 있습니다.
handle_connection이 잘 작동함을 확인하기 위해 데이터의 처음 부분을 비교하여 데이터가
MockTcpStream에 제대로 쓰여졌는 지 확인할 것입니다.
    use std::fs;
    #[async_std::test]
    async fn test_handle_connection() {
        let input_bytes = b"GET / HTTP/1.1\r\n";
        let mut contents = vec![0u8; 1024];
        contents[..input_bytes.len()].clone_from_slice(input_bytes);
        let mut stream = MockTcpStream {
            read_data: contents,
            write_data: Vec::new(),
        };
        handle_connection(&mut stream).await;
        let mut buf = [0u8; 1024];
        stream.read(&mut buf).await.unwrap();
        let expected_contents = fs::read_to_string("hello.html").unwrap();
        let expected_response = format!("HTTP/1.1 200 OK\r\n\r\n{}", expected_contents);
        assert!(stream.write_data.starts_with(expected_response.as_bytes()));
    }