This question already has an answer here:
- How to mock specific methods but not all of them in Rust? 2 answers
- How to mock external dependencies in tests? [duplicate] 1 answer
- How can I test stdin and stdout? 1 answer
- Is there a way of detecting whether code is being called from tests in Rust? 1 answer
- What is the proper way to use the `cfg!` macro to choose between multiple implementations? 1 answer
I have a function generates a salted hash digest for some data. For the salt, it uses a random u32
value. It looks something like this:
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())
}
In a test, I'd like to validate that it produces expected values, given a known salt and string. How do I mock (swizzle?) rand::thread_rng().next_u32()
in the test to generate a specific value? In other words, what could replace the comment in this example to make the test pass?
mod tests {
#[test]
fn test_hashes() {
// XXX How to mock ThreadRng::next_u32() to return 3892864592?
assert_eq!(hash("foo"), "e80866501cdda8af09a0a656");
}
}
Some approaches I've looked at:
-
I'm aware that the
ThreadRng
returned byrand::thread_rng()
implementsRngCore
, so in theory I could set a variable somewhere to store a reference to aRngCore
, and implement my own mocked variant to set during testing. I've taken this sort of approach in Go and Java, but I couldn't get the Rust type checker to allow it. -
I looked at the list of mock frameworks, such as MockAll, but they appear to be designed to mock a struct or trait to pass to a method, and this code doesn't pass one, and I wouldn't necessarily want users of the library to be able to pass in a
RngCore
. -
Use the
#[cfg(test)]
macro to call a different function specified in the tests module, then have that function read the value to return from elsewhere. This I got to work, but had to use an unsafe mutable static variable to set the value for the mocked method to find, which seems gross. Is there a better way?
As a reference, I'll post an answer using the #[cfg(test)]
+ unsafe mutable static variable technique, but hope there's a more straightforward way to do this sort of thing.
Aucun commentaire:
Enregistrer un commentaire