0 day streak
rust / expert
Snippet

Designing Compile-Time Mocking Interfaces for Unit Testing

This snippet showcases how to design unit tests using trait-based dependency injection for mocking. By decoupling the database operations through a trait, we construct a lightweight, compile-time mock object inside the test module to assert expected inputs and mock responses without external frameworks.

snippet.rs
rust
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
pub trait Database {
fn fetch_user_role(&self, user_id: u32) -> Result<String, &'static str>;
}
pub struct UserService<'a, D: Database> {
pub db: &'a D,
}
impl<'a, D: Database> UserService<'a, D> {
pub fn is_admin(&self, user_id: u32) -> bool {
self.db.fetch_user_role(user_id)
.map(|role| role == "Admin")
.unwrap_or(false)
}
}
#[cfg(test)]
mod tests {
use super::*;
struct MockDatabase {
expected_id: u32,
returned_role: Result<String, &'static str>,
}
impl Database for MockDatabase {
fn fetch_user_role(&self, user_id: u32) -> Result<String, &'static str> {
assert_eq!(user_id, self.expected_id);
self.returned_role.clone()
}
}
#[test]
fn test_admin_verification() {
let mock = MockDatabase {
expected_id: 42,
returned_role: Ok(String::from("Admin")),
};
let service = UserService { db: &mock };
assert!(service.is_admin(42));
}
}
Breakdown
1
pub trait Database
Declares a trait representing database operations to decouple dependencies.
2
pub struct UserService<'a, D: Database>
Defines a service that is parameterized over any type implementing the Database trait.
3
struct MockDatabase
A mock struct defined within the test module that holds test assertions and return data.
4
assert_eq!(user_id, self.expected_id);
Ensures the service calls the interface with the expected arguments during testing.