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

Simple Mocking in Rust

Simple Mocking in Rust

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 デファクトスタンダード的なものは特になさそう。