Rust tip: Use error handling in tests

Remove unwrap from tests and use ? instead!

Fredrik Park published on
2 min, 336 words

Categories: Tips

When writing tests, it is common to unwrap instead of doing proper error handling. While this is a valid approach for testing, it is not recommended when writing our application/library code. What if we could utilize Rusts powerful ? operator inside our tests as well?

Say for example, that we had this test to verify that we can do a reqwest call. There is a long string of .await.unwrap() statements, and it is not as nice as it could be. This is also not how you would write your production code, so you can't easily copy code between tests and regular code.

    #[tokio::test]
    async fn request_test() {

        let response = reqwest
            .get("http://example.com")
            .send()
            .await
            .unwrap()
            .text()
            .await
            .unwrap();
        assert_eq!(response, "Hello world");
    }

We can rewrite our tests to return a Result instead, which allows us to use the ? operator to make our tests feel more like ordinary Rust code.

    type TestResult<T> = std::result::Result<(), Box<dyn error::Error>>;

    #[tokio::test]
    async fn request_test() -> TestResult<()> {

        let response = reqwest
            .get("http://example.com")
            .send()
            .await?
            .text()
            .await?;
        assert_eq!(response, "Hello world");

        Ok(())
    }

While this is a small example, it really pays off doing this in larger tests where there is a lot of interaction between different parts.

ℹ️ I generally just add anyhow to my dev dependencies

cargo add --dev anyhow
    #[tokio::test]
    async fn request_test() -> anyhow::Result<()> {

        let response = reqwest
            .get("http://example.com")
            .send()
            .await?
            .text()
            .await?;
        assert_eq!(response, "Hello world");

        Ok(())
    }