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.