测试 future 和streams,如何创建一个假Context?

Rbj*_*bjz 2 unit-testing future rust async-await

我正在尝试弄清楚如何对我的 Stream 进行单元测试fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {todo!()}

它需要一个cx传递给嵌套流的上下文。我的测试和测试代码可以不需要,但我必须提供一些才能进行测试。

铁锈游乐场

use futures::ready;
use futures::stream::Stream;
use pin_project::pin_project;
use std::collections::VecDeque;
use std::pin::Pin;
use std::task::{Context, Poll}; // 0.4.22

#[pin_project]
pub struct MyStream<T>(#[pin] T);

impl<T: Stream> Stream for MyStream<T> {
    type Item = ();
    fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
        let _ignored = ready!(self.project().0.poll_next(cx));
        Poll::Ready(Some(()))
    }
}

#[test]
fn test1() {
    let setup = TestStream::from(vec![Poll::Ready(Some(true))]);
    let sut = MyStream(setup);

    // where do I get a fake Context<>?
    assert_eq!(Pin::new(&mut sut).poll_next(cx), Poll::Ready(Some(())))
}

#[pin_project]
struct TestStream<I> {
    items: VecDeque<Poll<Option<I>>>,
}
impl<T: IntoIterator<Item = Poll<Option<I>>>, I> From<T> for TestStream<I> {
    fn from(from: T) -> Self {
        TestStream {
            items: from.into_iter().collect(),
        }
    }
}
impl<I> Stream for TestStream<I> {
    type Item = I;
    fn poll_next(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
        if let Some(item) = self.project().items.pop_front() {
            item
        } else {
            Poll::Ready(None)
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

Rbj*_*bjz 6

我终于找到了 noop 唤醒器:

游乐场

#[test]
fn test1() {
    let waker = futures::task::noop_waker_ref();
    let mut cx = std::task::Context::from_waker(waker);
    let setup = TestStream::from(vec![Poll::Ready(Some(true))]);
    let mut sut = MyStream(setup);

    assert_eq!(Pin::new(&mut sut).poll_next(&mut cx), Poll::Ready(Some(())))
}
Run Code Online (Sandbox Code Playgroud)

感谢@rodrigo 的正确答案。