0 Tage Serie
rust / expert
Snippet

Mocking von Abhängigkeiten mit Thread-Lokalem Zustand

Das Mocken von Abhängigkeiten in multithreaded Test-Runnern kann zu Race Conditions führen, wenn ein globaler Zustand verwendet wird. Durch die Nutzung von thread-lokalem Speicher (thread_local!) können Sie Mock-Verhalten sicher injizieren, das nur den aktuellen Testthread betrifft, was eine sichere parallele Ausführung von Unit-Tests ohne externe Testabhängigkeiten ermöglicht.

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
use std::cell::RefCell;
thread_local! {
static MOCK_DB_RESPONSE: RefCell<Option<Result<String, &'static str>>> = const { RefCell::new(None) };
}
pub fn fetch_user_data(user_id: u32) -> Result<String, &'static str> {
let mut mock_result = None;
MOCK_DB_RESPONSE.with(|cell| {
if let Some(ref res) = *cell.borrow() {
mock_result = Some(res.clone());
}
});
if let Some(result) = mock_result {
result
} else {
Ok(format!("Real User Data for {}", user_id))
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_fetch_user_data_mocked() {
MOCK_DB_RESPONSE.with(|cell| {
*cell.borrow_mut() = Some(Err("Database Timeout"));
});
let result = fetch_user_data(42);
assert_eq!(result, Err("Database Timeout"));
MOCK_DB_RESPONSE.with(|cell| {
*cell.borrow_mut() = None;
});
}
}
Erklärung
1
thread_local! {
Deklariert eine thread-lokale statische Variable, die für jeden ausführenden Thread isoliert ist.
2
MOCK_DB_RESPONSE.with(|cell| {
Greift auf die thread-lokale RefCell zu, indem ein Closure an die mit()-Methode übergeben wird.
3
assert_eq!(result, Err("Database Timeout"));
Verifiziert, dass die Funktion den simulierten Fehler dynamisch abgefangen hat, anstatt die echte Logik auszuführen.