Slide 1

Slide 1 text

Simple Mocking in Rust Rust入門者の集い #5 @11Takanori

Slide 2

Slide 2 text

About Me ● @11Takanori ● 仕事だと、主にKotlin、たまにClojure、Dart、ごくたまにRust、 Elixirを使ってる

Slide 3

Slide 3 text

mockを使いたい理由 マイクロサービスA,B,Cがあるとする 1. マイクロサービスA,B,Cを組み合わせたE2Eを書く 2. マイクロサービスA単独のE2Eを書く ← 別のマイクロサービスをmockしたい 3. 2が通るようになるまで単体テストと実装を繰り返す(クリーンアーキテクチャのレイ ヤごと) ← 別のレイヤをmockしたい 4. マイクロサービスBに対しても同様 5. マイクロサービスCに対しても同様 6. マイクロサービスA,B,Cを組み合わせたE2Eが通る こんな感じで開発していると、mockしたくなる

Slide 4

Slide 4 text

単体テストのmock 今回はライブラリを使用せず、ユーザーにメールを 送る処理を素朴にmockする

Slide 5

Slide 5 text

#[derive(Clone)] struct Email { from: String, to: String, msg: String, } struct User { address: String, } trait EmailSender { fn send_mail(&self, msg: &Email) -> Result; //mock対象 } 実装

Slide 6

Slide 6 text

// テスト対象 fn publish_news(msg: &str, sender: &EmailSender, users: &[User]) -> u32 { let mut count = 0; let mut mail = Email { from: "[email protected]".to_string(), to: "".to_string(), msg: msg.to_string(), }; for user in users { mail.to = user.address.to_string(); match sender.send_mail(&mail) { // send_mail(&mail)をmockしたい Ok(_) => count += 1, Err(msg) => println!("Failed to send mail: {}", msg), } } count } 実装

Slide 7

Slide 7 text

struct MockEmailSender { // send_mailの引数の格納先 sent_mails: RefCell>, // RefCellは不変値を可変借用できる } impl MockEmailSender { fn new() -> Self { MockEmailSender { sent_mails: RefCell::new(Vec::new()), } } } impl EmailSender for MockEmailSender { fn send_mail(&self, mail: &Email) -> Result { // RefCellに格納しないと&mut selfを使うことになり、シグニチャーが一致しなくなる self.sent_mails.borrow_mut().push(mail.clone()); Ok("200 OK".to_string()) } } テスト

Slide 8

Slide 8 text

#[test] fn send_mail_to_users() { let user1 = User { address: "[email protected]".to_string(), }; let user2 = User { address: "[email protected]".to_string(), }; let send = publish_news("hello world", &MockEmailSender::new(), &[user1, user2]); assert_eq!(send, 2) // 意図した戻り値になっていることをチェック } テスト

Slide 9

Slide 9 text

#[test] fn send_correct_mail() { let user = User { address: "[email protected]".to_string(), }; let sender = MockEmailSender::new(); publish_news("hello world", &sender, &[user]); let mails = sender.sent_mails.borrow(); // Ref> assert_eq!(mails.len(), 1); // send_mailを呼んだ回数をチェック assert_eq!(mails[0].from, "[email protected]"); // 引数のチェック assert_eq!(mails[0].to, "[email protected]"); // 引数のチェック assert_eq!(mails[0].msg, "hello world"); // 引数のチェック } テスト

Slide 10

Slide 10 text

Rustのmockライブラリ ● Mockers (nightly) ● Double ● Mock_Derive (nightly) ● Galvanic-mock (nightly) ● Pseudo ● Mock-it ● Simulacrum デファクトスタンダード的なものは特になさそう。