У меня есть функция, генерирующая соленый хеш-дайджест для некоторых данных. Для соли используется случайное значение u32
. Это выглядит примерно так:
use rand::RngCore;
use std::collections::hash_map::DefaultHasher;
use std::hash::Hasher;
fn hash(msg: &str) -> String {
let salt = rand::thread_rng().next_u32();
let mut s = DefaultHasher::new();
s.write_u32(salt);
s.write(msg.as_bytes());
format!("{:x}{:x}", &salt, s.finish())
}
В тесте я хотел бы проверить, что он выдает ожидаемые значения с учетом известной соли и строки. Как мне имитировать (swizzle?) rand::thread_rng().next_u32()
в тесте, чтобы генерировать конкретное значение? Другими словами, чем можно заменить комментарий в этом примере, чтобы тест прошел?
mod tests {
#[test]
fn test_hashes() {
// XXX How to mock ThreadRng::next_u32() to return 3892864592?
assert_eq!(hash("foo"), "e80866501cdda8af09a0a656");
}
}
Некоторые подходы, на которые я смотрел:
Мне известно, что
ThreadRng
возвращаетrand::thread_rng()
реализуетRngCore
, поэтому теоретически я мог бы где-нибудь установить переменную для хранения ссылки наRngCore
и реализовать свой собственный издевательский вариант для установки во время тестирования. Я использовал такой подход в Go и Java, но не смог заставить средство проверки типов Rust разрешить его.Я просмотрел список фиктивных фреймворков, таких как MockAll, но оказалось, что они предназначены для имитации struct или типаж для передачи методу, а этот код не передает его, и я бы не хотел, чтобы пользователи библиотеки могли передавать
RngCore
.Используйте макрос
#[cfg(test)]
для вызова другой функции, указанной в модуле тестов, а затем заставьте эту функцию считать значение, которое нужно вернуть из другого места. Это я начал работать, но мне пришлось использовать небезопасную изменяемую статическую переменную, чтобы установить значение для насмешливого метода, которое нужно найти, что кажется грубым. Есть ли способ лучше?
В качестве справки я опубликую ответ, используя метод #[cfg(test)]
+ небезопасная изменяемая статическая переменная, но надеюсь, что есть более простой способ сделать такие вещи.