🧐

Rust で外部依存に対して mock test を書く

2021/09/20に公開

目的

外部の crate に依存している場合などで、テストが素直に書けない問題を解決したい。

方針

https://github.com/asomers/mockall
mockall という mock test 用のライブラリを使って依存部分を mock してテストを書く。
依存部分を直接 mock することはできなかったので、trait で interface 部分を定義して、そこを mock する形を取る。

手順

mockall を入れる

Cargo.toml
[dependencies]
mockall = "^0.10.2"

interface となる trait を定義する

#[async_trait]
pub trait Printer {
    // `&str` の部分を external crate を使って書ける
    async fn print(&self, message: &str);
}

interface を mock 化する

#[cfg_attr(test, mockall::automock)]
#[async_trait]
pub trait Printer {
    async fn print(&self, &str);
}

trait を使う関数を定義(テストしたい関数)

pub async fn printer_print(printer: &Printer) {
    printer.print("hoge")
    .await;
}

テストを書く

#[cfg(test)]
mod tests {
    use super::*;

    #[tokio::test]
    async fn test_printer_print() {
        // `#[cfg_attr(test, mockall::automock)]` で定義すると `MockHoge` の形で呼べるようになる
        let mut printer = MockPrinter::new();

        // `expect_hoge` で `hoge` 関数を mock できる
        printer.expect_print().times(1).return_const(());

        printer_print(printer).await
    }
}

expect_method に対してできること

ref: https://docs.rs/mockall/0.10.2/mockall/examples/__mock_MockFoo_Foo/__foo/struct.Expectation.html

サンプル実装

https://github.com/tktcorporation/discord-speech-bot/blob/d15b3239a8bb1fd09c4996295f21abba352cc5f3/src/handler/usecase/set_help_message_to_activity.rs#L19-L30

Discussion