I have troubles figuring out unit tests for the methods of the target struct.
I have a method random_number that returns a random value based on the att
How to mock specific methods but not all of them in Rust?
As you have already learned, you cannot replace methods on a type. The only thing you can do is move the methods to a trait and then provide production and test-specific implementations of that trait. How you structure the trait determines the granularity of what you are able to test.
Depending on your use case, you might be able to use a default implementation:
trait SomeRng {
fn random_number(&self) -> u64;
fn plus_one(&self) -> u64 {
self.random_number() + 1
}
}
struct RngTest(u64);
impl SomeRng for RngTest {
fn random_number(&self) -> u64 {
self.0
}
}
#[test]
fn plus_one_works() {
let rng = RngTest(41);
assert_eq!(rng.plus_one(), 42);
}
Here, random_number is a required method, but plus_one has a default implementation. Implementing random_number gives you plus_one by default. You could also choose to implement plus_one if you could do it more efficiently.
The real rand crate uses two traits:
Rng
pub trait Rng: RngCore { /* ... */ }
An automatically-implemented extension trait on
RngCoreproviding high-level generic methods for sampling values and other convenience methods.
RngCore
pub trait RngCore { /* ... */ }
The core of a random number generator.
This splits the core interesting parts of the implementation from the helper methods. You can then control the core and test the helpers:
trait SomeRngCore {
fn random_number(&self) -> u64;
}
trait SomeRng: SomeRngCore {
fn plus_one(&self) -> u64 {
self.random_number() + 1
}
}
impl SomeRng for R {}
struct RngTest(u64);
impl SomeRngCore for RngTest {
fn random_number(&self) -> u64 {
self.0
}
}
#[test]
fn plus_one_works() {
let rng = RngTest(41);
assert_eq!(rng.plus_one(), 42);
}