How to test a method inside an implementation in Rust [closed] - testing

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 2 years ago.
Improve this question
I'm trying to increase the test coverage in my Rust application. I have read lots about testing public functions and testing private functions and adding the "tests" directory in order to add integration tests. But I have not read anything about testing of methods within an implementation. I've tried googling a bit for this but I'm not finding anything.
Here is a simple example, is this how I am meant to implement the testing?
struct Rectangle {
width: usize,
length: usize,
}
impl Rectangle {
pub fn new(width: usize, length: usize) -> Rectangle {
Rectangle {
width,
length,
}
}
fn area(&mut self) -> usize {
self.width * self.length
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_rectangle() {
let mut rectangle = Rectangle::new(4, 5);
assert_eq!(20, rectangle.area())
}
}

Yes, that is exactly how you are meant to test struct methods. The Rust book has a chapter called Test Organization which states:
The purpose of unit tests is to test each unit of code in isolation from the rest of the code to quickly pinpoint where code is and isn’t working as expected. You’ll put unit tests in the src directory in each file with the code that they’re testing. The convention is to create a module named tests in each file to contain the test functions and to annotate the module with cfg(test).
Another common test organization methods is using documentation tests. rustdoc supports executing your documentation examples as tests. So running cargo test on the example below would cause the area function to execute as a test:
impl Rectangle {
/// ```rust
/// use crate::Rectangle;
///
/// let mut rectangle = Rectangle::new(4, 5);
/// assert_eq!(20, rectangle.area())
/// ```
fn area(&mut self) -> usize {
self.width * self.length
}
}

Related

How do I use rust traits to abstract HTTP call for tests?

Coming from Go there are a lot of interfaces you can use to do something like the below:
async fn get_servers(client: &dyn std::marker::Send) -> Result<String, impl std::error::Error> {
let servers_str = client.send().await?.text()
let v: Value = serde_json::from_str(servers_str)?;
println!("{:?}", v);
Ok(servers_str.to_string())
}
// ...
get_servers(client.get(url))
I could pass in something that just implemented the send and return the text. That way makes the code testable. I thought maybe the send auto trait would do that but apparently not. Says send not found. Maybe some kind of impl requestbuilder?
In general, this is absolutely possible and (correct me if I'm wrong) even advised. It's a programming paradigm called dependency injection.
Simplified, this means in your case, pass in the dependent object via an interface (or in Rust: trait) so you can replace it at test time with an object of a different type.
Your mistake here is that the std::marker::Send trait does not what you think it does; it marks objects for being transferrable between threads. It's closely linked to std::marker::Sync, meaning, it can be accessed by multiple threads without causing race conditions.
While many libraries already have traits you can use for that purpose, in a lot of cases you will have to set up your own trait. Here, for example, we have a hello world function, that gets tested by replacing its printer with a different one, specialized for testing. We achieve that by passing the printer into the hello world function through the abstraction of a trait, as already mentioned.
trait HelloWorldPrinter {
fn print_text(&mut self, msg: &str);
}
struct ConsolePrinter;
impl HelloWorldPrinter for ConsolePrinter {
fn print_text(&mut self, msg: &str) {
println!("{}", msg);
}
}
// This is the function we want to test.
// Note that we are using a trait here so we can replace the actual
// printer with a test mock when testing.
fn print_hello_world(printer: &mut impl HelloWorldPrinter) {
printer.print_text("Hello world!");
}
fn main() {
let mut printer = ConsolePrinter;
print_hello_world(&mut printer);
}
#[cfg(test)]
mod tests {
use super::*;
struct TestPrinter {
messages: Vec<String>,
}
impl TestPrinter {
fn new() -> Self {
Self { messages: vec![] }
}
}
impl HelloWorldPrinter for TestPrinter {
fn print_text(&mut self, msg: &str) {
self.messages.push(msg.to_string());
}
}
#[test]
fn prints_hello_world() {
let mut printer = TestPrinter::new();
print_hello_world(&mut printer);
assert_eq!(printer.messages, ["Hello world!"]);
}
}
When doing cargo run:
Hello world!
When doing cargo test:
Running unittests src/main.rs
running 1 test
test tests::prints_hello_world ... ok
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
As a little explanation, if that code doesn't explain itself:
we create a trait HelloWorldPrinter whic his the only thing our print_hello_world() function knows about.
we define a ConsolePrinter struct that we use at runtime to print the message. The ConsolePrinter of course has to implement HelloWorldPrinter to be usable with the print_hello_world() function.
for testing, we write the TestPrinter struct that we use instead of the ConsolePrinter. Instead of printing, it stores what it received so we can test whether it got passed the correct message. Of course, the ConsolePrinter also has to implement the HelloWorldPrinter trait to be usable with print_hello_world().
I hope that goes into the direction of your question. If you have any questions, feel free to discuss further.
I can't directly tell you what you should write to solve your problem, as your question is quite vague, but this should be the toolset you need to solve your problem. I hope.

How do I place a Rust module in a separate file? [duplicate]

This question already has answers here:
Can't understand Rust module system
(1 answer)
Split a module across several files
(7 answers)
How to use one module from another module in a Rust cargo project?
(3 answers)
Closed 2 years ago.
The code below is adapted from "the book" (rustup docs --book), and works as intended in this form - as a single .rs file. I simply want the module to reside in a separate file. I've read Chapter 7 of "the book", "Managing Growing Projects with Packages, Crates, and Modules". I'm just not getting "it". My notion is that the "main" code belongs in main.rs, and the module may need to be in lib.rs, but the exact forms and placements are still a mystery. The chapter often states to run "cargo new/build whatever", but doesn't state from what directory. Likewise, it states that src/main.rs or src/lib.rs should look like such-and-such for a particular example, but it's not clear (without a full path) if one "src" directory is actually in the same location as another.
So, I imagine that's there more than one way to do this, but I'll be happy with a relatively simple answer. In this instance, I only care that the module is accessible from the main() function seen below.
mod guess_mod {
pub struct Guess {
value: i32,
}
impl Guess {
pub fn new(value: i32) -> Guess {
if value < 1 || value > 100 {
panic!("Guess value must be between 1 and 100, got {}.", value);
}
Guess{value}
}
pub fn value(&self) -> i32 {
self.value
}
}
}
use guess_mod::Guess;
fn print_guess_value(guess: Guess) {
println!("The value of the guess is {} ", guess.value());
}
fn main() {
let g = Guess::new(18);
print_guess_value(g);
}
You could create the following folder structure within src:
src
├── guess
│   └── mod.rs
└── main.rs
Your guess module could either live in a file called guess.rs or in a folder named guess/ with a mod.rs inside (as in the structure above).
In your mod.rs (or guess.rs) you could put the content of module):
pub struct Guess {
value: i32,
}
impl Guess {
pub fn new(value: i32) -> Guess {
if value < 1 || value > 100 {
panic!("Guess value must be between 1 and 100, got {}.", value);
}
Guess { value }
}
pub fn value(&self) -> i32 {
self.value
}
}
In your main.rs you could use it as follows:
// This declaration will look for a file named `guess.rs` or `guess/mod.rs`
mod guess;
use guess::Guess;
fn print_guess_value(guess: Guess) {
println!("The value of the guess is {} ", guess.value());
}
fn main() {
let g = Guess::new(18);
print_guess_value(g);
}
You run cargo from the root of your folder structure (i.e src).
If the rust book is not clear enough for you, perhaps try Rust by Example: https://doc.rust-lang.org/rust-by-example/mod.html
Maybe you are mixing the concepts of crates and modules. They are somewhat related but different.
Crates are separated units of compilation, distribution, versioning, and dependency management.
Modules are pieces of a crate that are logically separated, with visibility barriers maybe also compiled separately, but finally linked together, and bundled into a crate.
If you talk C, you can see crates as libraries and modules as compilation units. Or if you talk C++ or C# you can see modules as namespaces. Except that executables are also crates, but of a different kind.
Now, how do you create them? The easiest are modules. There are three options:
Modules #1
You write the module inline inside other file:
//src/main.rs
mod foo {
pub fn test() {}
}
fn main() {
foo::test();
}
Modules #2
You write the module in a separated file, in the same source directory:
//src/main.rs
mod foo;
fn main() {
foo::test();
}
//src/foo.rs
pub fn test() {}
You can add submodules of foo in a subdirectory named src/foo.
Modules #3
You write the module in a subdirectory, the file must be named mod.rs:
//src/main.rs
mod foo;
fn main() {
foo::test();
}
//src/foo/mod.rs
pub fn test() {}
You can use the subdirectory src/foo to create submodules of foo.
Crates
The easiest way to link a crate is to add it to the [dependencies] section of your Cargo.toml. Then cargo is just magic.
When you create a crate, it may have 0 or 1 libraries and 0 or many binaries. A usual pattern is to create dual Cargo project, that has library and a binary all together. Then you will have a src/main.rs and a src/lib.rs files. The dependency is handled automatically.
//src/main.rs
fn main() {
foo::test();
}
//src/lib.rs
pub fn test() {}
For more complex projects you can split your source into several crates, and handle all them together into a workspace, but I think that is out of scope of this question.

Is there a way to convert a trait reference to an object of another unconnected type? [duplicate]

This question already has answers here:
How to get a reference to a concrete type from a trait object?
(2 answers)
Closed 4 years ago.
I have a collection of interfaces that are loaded dynamically from shared libraries. I want to be able to convert those downcasted interfaces to their original type (trait).
struct A {}
fn abstract_a<'l>() -> &'l Any { return &A{} }
trait TargetTrait { fn some_method(); }
impl TargetTrait for A { fn some_method() { println!("HELLO"); } }
fn main() {
let x: &Any = abstract_a();
let y: &TargetTrait = magic_conversion<&TargetTrait> (x);
}
// question: does 'magic_conversion'(or 'dynamic_cast') exist? what is it?
While loading these is not a problem, I have no idea how to get target functionality with such interface. In other words:
/* simplified for readability */
// this part is known
let some_lib = loadlib("path/to/lib.so")
let some_interface: &Any = some_lib.loadfunc<&Any>("constructor_func")()
/* loader does not know what target type constructor has, so it presumes 'Any' */
// the problem:
let dependent_class = Some(class)
dependent_class.graphics = dynamic_cast<IGraphics>(some_interface)
In this example, dependent_class uses an extern interface and does not care about handling libloading and all of that complicated stuff.
If there is another way to achieve my goal, I would also be very happy to see it, but the only solution I came up with is 'dynamic_cast'
I think what you're looking for is downcast_ref::<A>:
let y: &TargetTrait = Any::downcast_ref::<A>(x).expect("Expected an A");
You have to specify the concrete type A. Any trait objects don't hold any information about what traits the underlying type implements, so you can't "cross-cast" from &Any to &TargetTrait directly; you have to know the underlying type.
The expect will panic if downcast_ref returns None; if that's not what you want, you have to decide what you want to happen when x is not an A and match against the result of downcast_ref instead.

How do I test private methods in Rust?

How do I test private methods in Rust? I didn't find any information about it. There's no information in the documentation either.
When using #[test], there’s nothing special about private or public methods—you’re just writing perfectly normal functions that can access anything they can access.
fn private_function() {
}
#[test]
fn test_private_function() {
private_function()
}
External tests, such as tests/*.rs and examples/*.rs if you’re using Cargo, or doc tests, do not get access to private members; nor should they: such tests are designed to be public API tests, not to be dealing with implementation details.
I don't know if this issue is still open for you, but I found some documentation about it :
Test Organization
What I retained from it is that you can test private method but only if the test can see it (i.e. they are in the same scope), since tests follow the visibility rules as any other function.
Here is a working example :
pub fn add_two(a: i32) -> i32 {
internal_adder(a, 2)
}
fn internal_adder(a: i32, b: i32) -> i32 {
a + b
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn internal() {
assert_eq!(4, internal_adder(2, 2));
}
}
All in all, please remember that the debate wether private methods should or should not be tested is still open within the test community. Both sides have valid argument and the correct answer only relies on you, your vision on testing procedure and the context of your project.

Providing an implementation when both trait and type are not in this crate [duplicate]

This question already has answers here:
How do I implement a trait I don't own for a type I don't own?
(3 answers)
Closed 7 years ago.
I want to provide an implementation of a trait ToHex (not defined by me, from serialize) for a primitive type u8:
impl ToHex for u8 {
fn to_hex(&self) -> String {
self.to_str_radix(16)
}
}
The problem is I get this compiler error:
error: cannot provide an extension implementation where both trait and type are not defined in this crate
I understand the reason of this error and its logic, this is because both the trait and the primitive type are external to my code. But how can I handle this situation and provide an ToHex implementation for u8? And more generally how do you handle this kind of issue, it seems to me that this problem must be common and it should be possible and easy to extend types like this?
You should use a newtype struct to do this:
pub struct U8(pub u8)
impl ToHex for U8 {
fn to_hex(&self) -> String {
let U8(x) = *self;
x.to_str_radix(16)
}
}
This does mean, however, that you should wrap u8 into U8 where you need to perform this conversion:
let x: u8 = 127u8
// println!("{}", x.to_hex()); // does not compile
println!("{}", U8(x).to_hex());
This is absolutely free in terms of performance.
I realize this is almost a year old, but the answer was never accepted and I think I've found an alternate solution, that I thought would be good to document here.
In order to extend the functionality of the u8 through traits, instead of trying to extend ToHex, why not create a new trait?
trait MyToHex {
fn to_hex(&self) -> String;
}
impl MyToHex for u8 {
fn to_hex(&self) -> String {
format!("{:x}", *self)
}
}
then used like so
fn main() {
println!("{}", (16).to_hex());
}
This has the advantage that you don't have to wrap every u8 variable with a new and superfluous data type.
The disadvantage is that you still can't use a u8 in a external function (i.e std library, or one you have no control over) that requires the ToHex trait (Vladimir Matveev's solution works in this case), but from OP it sounds like all you want to do is extend u8 only inside your code.