0 Tage Serie
rust / expert
Snippet

Isolieren von Seiteneffekten in Tests mittels Thread-lokalem Mocking

Beim Schreiben von Unit-Tests in Rust laufen diese standardmäßig parallel. Um globale Funktionen oder FFI-Zustände ohne Race-Conditions sicher zu mocken, können wir `thread_local!` verwenden. Dies isoliert Mock-Zustände ausschließlich auf den Thread des jeweiligen Tests.

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
use std::cell::RefCell;
thread_local! {
static MOCK_DB_RESPONSE: RefCell<Option<Result<String, &'static str>>> = const { RefCell::new(None) };
}
fn fetch_data_from_db() -> Result<String, &'static str> {
MOCK_DB_RESPONSE.with(|mock| {
if let Some(ref response) = *mock.borrow() {
response.clone()
} else {
Ok("real_production_data".to_string())
}
})
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_database_error_handling() {
MOCK_DB_RESPONSE.with(|mock| {
*mock.borrow_mut() = Some(Err("Timeout"));
});
assert_eq!(fetch_data_from_db(), Err("Timeout"));
MOCK_DB_RESPONSE.with(|mock| *mock.borrow_mut() = None);
}
}
Erklärung
1
static MOCK_DB_RESPONSE: RefCell<Option<Result<...>>> = ...
Deklariert eine Thread-lokale statische Variable mit einer RefCell zur Speicherung des Mock-Ergebnisses.
2
MOCK_DB_RESPONSE.with(|mock| {
Greift über einen Scoped-Closure-Mechanismus auf den an den Thread gebundenen Mock-Container zu.
3
*mock.borrow_mut() = Some(Err("Timeout"));
Konfiguriert den Fehlerzustand auf dem aktuellen Test-Thread, ohne andere parallel laufende Tests zu beeinflussen.