1
votes

How do you test your futures which are meant to be run in the Tokio runtime?

fn fut_dns() -> impl Future<Item = (), Error = ()> {
    let f = dns::lookup("www.google.de", "127.0.0.1:53");
    f.then(|result| match result {
        Ok(smtptls) => {
            println!("{:?}", smtptls);
            assert_eq!(smtptls.version, "TLSRPTv1");
            assert!(smtptls.rua.len() > 0);
            assert_eq!(smtptls.rua[0], "mailto://...");
            ok(())
        }
        Err(e) => {
            println!("error: {:?}", e);
            err(())
        }
    })
}

#[test]
fn smtp_log_test() {
    tokio::run(fut_dns());
    assert!(true);
}

The future runs and the thread of the future panics on an assert. You can read the panic in the console, but the test doesn't recognize the threads of tokio::run.

The How can I test a future that is bound to a tokio TcpStream? doesn't answer this, because it simply says: A simple way to test async code may be to use a dedicated runtime for each test

I do this!

My question is related to how the test can detect if the future works. The future needs a started runtime environment.

The test is successful although the future asserts or calls err().

So what can I do?

1
Is fut_dns your production code or is it test code? If it's test code, why is it a separate function from the #[test] function? If it's production code, why does it contain assertions? - Shepmaster
It's a separate function because of DRY. I will check your 2nd comment link above. - Markus

1 Answers

2
votes

Do not write your assertions inside the future.

As described in How can I test a future that is bound to a tokio TcpStream?, create a Runtime to execute your future. As described in How do I synchronously return a value calculated in an asynchronous Future in stable Rust?, compute your value and then exit the async world:

fn run_one<F>(f: F) -> Result<F::Item, F::Error>
where
    F: IntoFuture,
    F::Future: Send + 'static,
    F::Item: Send + 'static,
    F::Error: Send + 'static,
{
    let mut runtime = tokio::runtime::Runtime::new().expect("Unable to create a runtime");
    runtime.block_on(f.into_future())
}

#[test]
fn smtp_log_test() {
    let smtptls = run_one(dns::lookup("www.google.de", "127.0.0.1:53")).unwrap();
    assert_eq!(smtptls.version, "TLSRPTv1");
    assert!(smtptls.rua.len() > 0);
    assert_eq!(smtptls.rua[0], "mailto://...");
}