Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Simple Mocking in Rust

Sponsored · Your Podcast. Everywhere. Effortlessly. Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.

Simple Mocking in Rust

Avatar for Takanori Ishibashi

Takanori Ishibashi

September 05, 2018
Tweet

Other Decks in Technology

Transcript

  1. 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したくなる
  2. #[derive(Clone)] struct Email { from: String, to: String, msg: String,

    } struct User { address: String, } trait EmailSender { fn send_mail(&self, msg: &Email) -> Result<String, String>; //mock対象 } 実装
  3. // テスト対象 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 } 実装
  4. struct MockEmailSender { // send_mailの引数の格納先 sent_mails: RefCell<Vec<Email>>, // RefCellは不変値を可変借用できる }

    impl MockEmailSender { fn new() -> Self { MockEmailSender { sent_mails: RefCell::new(Vec::new()), } } } impl EmailSender for MockEmailSender { fn send_mail(&self, mail: &Email) -> Result<String, String> { // RefCellに格納しないと&mut selfを使うことになり、シグニチャーが一致しなくなる self.sent_mails.borrow_mut().push(mail.clone()); Ok("200 OK".to_string()) } } テスト
  5. #[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) // 意図した戻り値になっていることをチェック } テスト
  6. #[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<Vec<Email>> 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"); // 引数のチェック } テスト
  7. Rustのmockライブラリ • Mockers (nightly) • Double • Mock_Derive (nightly) •

    Galvanic-mock (nightly) • Pseudo • Mock-it • Simulacrum デファクトスタンダード的なものは特になさそう。