New crate: Mockall

I've just published Mockall[1]: a new mocking library. Mocking is a powerful testing technique: you create mock objects that implement the same interface as real object, but whose responses are controlled by the test code. It's a great way to unit test the middle of your stack, or to inject errors at any level. For example, the test code below injects an error, and discovers that query_and_capitalize has insufficient error handling

use mockall::*;
use mockall::predicate::*;
use std::io::{Error, ErrorKind, Result};

#[automock]
trait Database {
    fn query(&self, key: u32) -> Result<String>;
}

fn query_and_capitalize(db: &Database, key: u32) -> String {
    db.query(key)
        .unwrap()   // No error handling!
        .to_uppercase()
        .to_string()
}

#[test]
fn query_error() {
    let mut mock = MockDatabase::new();
    mock.expect_query()
        .with(eq(4))
        .return_once(|_| Err(Error::from(ErrorKind::NotFound)));
    assert_eq!("NOTFOUND", query_and_capitalize(&mock, 4));
}

Rust already has several mocking libraries, but Mockall has several powerful features that the others all lack:

  • It can mock methods that return references
  • It supports where clauses in all positions
  • It can mock methods that use -> impl Trait return syntax
  • It can mock methods that return common Deref types like &str without using cumbersome global constants.
  • Its mock objects can be passed between threads, even if some methods use argument or return types that aren't Send.

Enjoy! And please don't hesitate to open any issues, even for questions.

[1] Technically, I published it a month ago, but it took awhile to shake out some bugs.

4 Likes