Welcome to Software Development on Codidact!
Will you help us build our independent community of developers helping developers? We're small and trying to grow. We welcome questions about all aspects of software development, from design to code to QA and more. Got questions? Got answers? Got code you'd like someone to review? Please join us.
Post History
is there a way to write MockIO so that I don't have to change the signature of IO::println() for the sake of the test class? Yes, implementing mock objects is one of the recommended uses for R...
Answer
#4: Post edited
- > is there a way to write MockIO so that I don't have to change the signature of IO::println() for the sake of the test class?
- Yes, implementing mock objects is [one of the recommended uses](https://doc.rust-lang.org/book/ch15-05-interior-mutability.html#a-use-case-for-interior-mutability-mock-objects) for `RefCell<T>`, according to the Rust book.
- By placing the vector in a `RefCell` you gain the ability to modify it (carefully!) via a non-`mut` reference.
- struct MockIO {
- outputs: RefCell<Vec<String>>,
- }
- impl IO for MockIO {
- fn println(&self, s: &str) {
- self.outputs.borrow_mut().push(s.to_string());
- }
- }
- I've also removed the `pub`s from the test code in this example: generally test code should live in the same module (or a sub-module) as the code it is testing, and does not need to be exposed publicly. If the struct *does* need to be exposed for some reason, the `RefCell` certainly shouldn't be `pub`, because it would be impossible to enforce the requirement that there is never more than one `borrow_mut()` active at once (otherwise the code will panic at runtime).
- > is there a better way to solve this problem altogether?
- Personally I think this approach is rather too complicated. I presume that it is not the act of *printing* that you want to test, but just that your class *generates* the correct string contents.
- I would test this by simply splitting the printing code from the string-generating code, then only test the generating code while assuming that the basic Rust functionality of printing to stdout works fine.
- E.g.
- impl Foo {
- fn make_hello() -> String {
- String::from("Hello, World!")
- }
- pub fn print_hello() {
- let line = make_hello();
- println!("{line}");
- }
- }
- Now you can write all the tests for `make_hello()` that you require by examining the returned string, without needing any abstracted IO traits.
- Note the different visibility of the two methods: `print_hello()` is `pub` because it is intended to be called by client code, whereas `make_hello()` is not `pub` because it is only intended to be called in unit tests within the same module. You could of course choose to make `make_hello()` public if there was a potential need for client code to generate an output string without immediately printing it.
- ### Organising tests
- Instead of adding a `#[cfg(test)]` to each individual chunk of test code, it is more idiomatic to put all of the test code in a `tests` submodule at the end of the module being tested. This makes the tests easy to find, and keeps them private while allowing them to access all of the code in the parent module due to Rust's module visibility rules.
- ```
- #[cfg(test)]
- mod tests {
- use super::*; // import everything from parent module
- // Define mock objects, other test-specific code here
- struct MockIO {
- outputs: RefCell<Vec<String>>,
- }
- impl IO for MockIO {
- // etc
- }
- // Actual test functions here
- #[test]
- fn make_hello_world() {
- // etc
- }
- }
- ```
- > is there a way to write MockIO so that I don't have to change the signature of IO::println() for the sake of the test class?
- Yes, implementing mock objects is [one of the recommended uses](https://doc.rust-lang.org/book/ch15-05-interior-mutability.html#a-use-case-for-interior-mutability-mock-objects) for `RefCell<T>`, according to the Rust book.
- By placing the vector in a `RefCell` you gain the ability to modify it (carefully!) via a non-`mut` reference.
- struct MockIO {
- outputs: RefCell<Vec<String>>,
- }
- impl IO for MockIO {
- fn println(&self, s: &str) {
- self.outputs.borrow_mut().push(s.to_string());
- }
- }
- I've also removed the `pub`s from the test code in this example: generally test code should live in the same module (or a sub-module) as the code it is testing, and does not need to be exposed publicly. If the struct *does* need to be exposed for some reason, the `RefCell` certainly shouldn't be `pub`, because it would be impossible to enforce the requirement that there is never more than one `borrow_mut()` active at once (otherwise the code will panic at runtime).
- > is there a better way to solve this problem altogether?
- Personally I think this approach is rather too complicated. I presume that it is not the act of *printing* that you want to test, but just that your class *generates* the correct string contents.
- I would test this by simply splitting the printing code from the string-generating code, then only test the generating code while assuming that the basic Rust functionality of printing to stdout works fine.
- E.g.
- impl Foo {
- fn make_hello() -> String {
- String::from("Hello, World!")
- }
- pub fn print_hello() {
- let line = make_hello();
- println!("{line}");
- }
- }
- Now you can write all the tests for `make_hello()` that you require by examining the returned string, without needing any abstracted IO traits.
- Note the different visibility of the two methods: `print_hello()` is `pub` because it is intended to be called by client code, whereas `make_hello()` is not `pub` because it is only intended to be called in unit tests within the same module. You could of course choose to make `make_hello()` public if there was a potential need for client code to generate an output string without immediately printing it.
- If you really do want to test printing rather than just string generation, or you find the allocation of `String` objects unacceptable for any reason, then you should use the `std::io::Write` trait exposed in the standard library (as recommended by Moshi in the comments) rather than defining your own.
- ### Organising tests
- Instead of adding a `#[cfg(test)]` to each individual chunk of test code, it is more idiomatic to put all of the test code in a `tests` submodule at the end of the module being tested. This makes the tests easy to find, and keeps them private while allowing them to access all of the code in the parent module due to Rust's module visibility rules.
- ```
- #[cfg(test)]
- mod tests {
- use super::*; // import everything from parent module
- // Define mock objects, other test-specific code here
- struct MockIO {
- outputs: RefCell<Vec<String>>,
- }
- impl IO for MockIO {
- // etc
- }
- // Actual test functions here
- #[test]
- fn make_hello_world() {
- // etc
- }
- }
- ```
#3: Post edited
- > is there a way to write MockIO so that I don't have to change the signature of IO::println() for the sake of the test class?
- Yes, implementing mock objects is [one of the recommended uses](https://doc.rust-lang.org/book/ch15-05-interior-mutability.html#a-use-case-for-interior-mutability-mock-objects) for `RefCell<T>`, according to the Rust book.
- By placing the vector in a `RefCell` you gain the ability to modify it (carefully!) via a non-`mut` reference.
- struct MockIO {
- outputs: RefCell<Vec<String>>,
- }
- impl IO for MockIO {
- fn println(&self, s: &str) {
- self.outputs.borrow_mut().push(s.to_string());
- }
- }
- I've also removed the `pub`s from the test code in this example: generally test code should live in the same module (or a sub-module) as the code it is testing, and does not need to be exposed publicly. If the struct *does* need to be exposed for some reason, the `RefCell` certainly shouldn't be `pub`, because it would be impossible to enforce the requirement that there is never more than one `borrow_mut()` active at once (otherwise the code will panic at runtime).
- > is there a better way to solve this problem altogether?
- Personally I think this approach is rather too complicated. I presume that it is not the act of *printing* that you want to test, but just that your class *generates* the correct string contents.
- I would test this by simply splitting the printing code from the string-generating code, then only test the generating code while assuming that the basic Rust functionality of printing to stdout works fine.
- E.g.
- impl Foo {
- fn make_hello() -> String {
- String::from("Hello, World!")
- }
- pub fn print_hello() {
- let line = make_hello();
- println!("{line}");
- }
- }
- Now you can write all the tests for `make_hello()` that you require by examining the returned string, without needing any abstracted IO traits.
- ### Organising tests
- Instead of adding a `#[cfg(test)]` to each individual chunk of test code, it is more idiomatic to put all of the test code in a `tests` submodule at the end of the module being tested. This makes the tests easy to find, and keeps them private while allowing them to access all of the code in the parent module due to Rust's module visibility rules.
- ```
- #[cfg(test)]
- mod tests {
- use super::*; // import everything from parent module
- // Define mock objects, other test-specific code here
- struct MockIO {
- outputs: RefCell<Vec<String>>,
- }
- impl IO for MockIO {
- // etc
- }
- // Actual test functions here
- #[test]
- fn make_hello_world() {
- // etc
- }
- }
- ```
- > is there a way to write MockIO so that I don't have to change the signature of IO::println() for the sake of the test class?
- Yes, implementing mock objects is [one of the recommended uses](https://doc.rust-lang.org/book/ch15-05-interior-mutability.html#a-use-case-for-interior-mutability-mock-objects) for `RefCell<T>`, according to the Rust book.
- By placing the vector in a `RefCell` you gain the ability to modify it (carefully!) via a non-`mut` reference.
- struct MockIO {
- outputs: RefCell<Vec<String>>,
- }
- impl IO for MockIO {
- fn println(&self, s: &str) {
- self.outputs.borrow_mut().push(s.to_string());
- }
- }
- I've also removed the `pub`s from the test code in this example: generally test code should live in the same module (or a sub-module) as the code it is testing, and does not need to be exposed publicly. If the struct *does* need to be exposed for some reason, the `RefCell` certainly shouldn't be `pub`, because it would be impossible to enforce the requirement that there is never more than one `borrow_mut()` active at once (otherwise the code will panic at runtime).
- > is there a better way to solve this problem altogether?
- Personally I think this approach is rather too complicated. I presume that it is not the act of *printing* that you want to test, but just that your class *generates* the correct string contents.
- I would test this by simply splitting the printing code from the string-generating code, then only test the generating code while assuming that the basic Rust functionality of printing to stdout works fine.
- E.g.
- impl Foo {
- fn make_hello() -> String {
- String::from("Hello, World!")
- }
- pub fn print_hello() {
- let line = make_hello();
- println!("{line}");
- }
- }
- Now you can write all the tests for `make_hello()` that you require by examining the returned string, without needing any abstracted IO traits.
- Note the different visibility of the two methods: `print_hello()` is `pub` because it is intended to be called by client code, whereas `make_hello()` is not `pub` because it is only intended to be called in unit tests within the same module. You could of course choose to make `make_hello()` public if there was a potential need for client code to generate an output string without immediately printing it.
- ### Organising tests
- Instead of adding a `#[cfg(test)]` to each individual chunk of test code, it is more idiomatic to put all of the test code in a `tests` submodule at the end of the module being tested. This makes the tests easy to find, and keeps them private while allowing them to access all of the code in the parent module due to Rust's module visibility rules.
- ```
- #[cfg(test)]
- mod tests {
- use super::*; // import everything from parent module
- // Define mock objects, other test-specific code here
- struct MockIO {
- outputs: RefCell<Vec<String>>,
- }
- impl IO for MockIO {
- // etc
- }
- // Actual test functions here
- #[test]
- fn make_hello_world() {
- // etc
- }
- }
- ```
#2: Post edited
- > is there a way to write MockIO so that I don't have to change the signature of IO::println() for the sake of the test class?
- Yes, implementing mock objects is [one of the recommended uses](https://doc.rust-lang.org/book/ch15-05-interior-mutability.html#a-use-case-for-interior-mutability-mock-objects) for `RefCell<T>`, according to the Rust book.
- By placing the vector in a `RefCell` you gain the ability to modify it (carefully!) via a non-`mut` reference.
- struct MockIO {
- outputs: RefCell<Vec<String>>,
- }
- impl IO for MockIO {
- fn println(&self, s: &str) {
- self.outputs.borrow_mut().push(s.to_string());
- }
- }
- I've also removed the `pub`s from the test code in this example: generally test code should live in the same module (or a sub-module) as the code it is testing, and does not need to be exposed publicly. If the struct *does* need to be exposed for some reason, the `RefCell` certainly shouldn't be `pub`, because it would be impossible to enforce the requirement that there is never more than one `borrow_mut()` active at once (otherwise the code will panic at runtime).
- > is there a better way to solve this problem altogether?
- Personally I think this approach is rather too complicated. I presume that it is not the act of *printing* that you want to test, but just that your class *generates* the correct string contents.
- I would test this by simply splitting the printing code from the string-generating code, then only test the generating code while assuming that the basic Rust functionality of printing to stdout works fine.
- E.g.
- impl Foo {
- fn make_hello() -> String {
- String::from("Hello, World!")
- }
- pub fn print_hello() {
- let line = make_hello();
- println!("{line}");
- }
- }
Now you can write all the tests for `make_hello()` that you require by examining the returned string, without needing any abstracted IO traits.
- > is there a way to write MockIO so that I don't have to change the signature of IO::println() for the sake of the test class?
- Yes, implementing mock objects is [one of the recommended uses](https://doc.rust-lang.org/book/ch15-05-interior-mutability.html#a-use-case-for-interior-mutability-mock-objects) for `RefCell<T>`, according to the Rust book.
- By placing the vector in a `RefCell` you gain the ability to modify it (carefully!) via a non-`mut` reference.
- struct MockIO {
- outputs: RefCell<Vec<String>>,
- }
- impl IO for MockIO {
- fn println(&self, s: &str) {
- self.outputs.borrow_mut().push(s.to_string());
- }
- }
- I've also removed the `pub`s from the test code in this example: generally test code should live in the same module (or a sub-module) as the code it is testing, and does not need to be exposed publicly. If the struct *does* need to be exposed for some reason, the `RefCell` certainly shouldn't be `pub`, because it would be impossible to enforce the requirement that there is never more than one `borrow_mut()` active at once (otherwise the code will panic at runtime).
- > is there a better way to solve this problem altogether?
- Personally I think this approach is rather too complicated. I presume that it is not the act of *printing* that you want to test, but just that your class *generates* the correct string contents.
- I would test this by simply splitting the printing code from the string-generating code, then only test the generating code while assuming that the basic Rust functionality of printing to stdout works fine.
- E.g.
- impl Foo {
- fn make_hello() -> String {
- String::from("Hello, World!")
- }
- pub fn print_hello() {
- let line = make_hello();
- println!("{line}");
- }
- }
- Now you can write all the tests for `make_hello()` that you require by examining the returned string, without needing any abstracted IO traits.
- ### Organising tests
- Instead of adding a `#[cfg(test)]` to each individual chunk of test code, it is more idiomatic to put all of the test code in a `tests` submodule at the end of the module being tested. This makes the tests easy to find, and keeps them private while allowing them to access all of the code in the parent module due to Rust's module visibility rules.
- ```
- #[cfg(test)]
- mod tests {
- use super::*; // import everything from parent module
- // Define mock objects, other test-specific code here
- struct MockIO {
- outputs: RefCell<Vec<String>>,
- }
- impl IO for MockIO {
- // etc
- }
- // Actual test functions here
- #[test]
- fn make_hello_world() {
- // etc
- }
- }
- ```
#1: Initial revision
> is there a way to write MockIO so that I don't have to change the signature of IO::println() for the sake of the test class? Yes, implementing mock objects is [one of the recommended uses](https://doc.rust-lang.org/book/ch15-05-interior-mutability.html#a-use-case-for-interior-mutability-mock-objects) for `RefCell<T>`, according to the Rust book. By placing the vector in a `RefCell` you gain the ability to modify it (carefully!) via a non-`mut` reference. struct MockIO { outputs: RefCell<Vec<String>>, } impl IO for MockIO { fn println(&self, s: &str) { self.outputs.borrow_mut().push(s.to_string()); } } I've also removed the `pub`s from the test code in this example: generally test code should live in the same module (or a sub-module) as the code it is testing, and does not need to be exposed publicly. If the struct *does* need to be exposed for some reason, the `RefCell` certainly shouldn't be `pub`, because it would be impossible to enforce the requirement that there is never more than one `borrow_mut()` active at once (otherwise the code will panic at runtime). > is there a better way to solve this problem altogether? Personally I think this approach is rather too complicated. I presume that it is not the act of *printing* that you want to test, but just that your class *generates* the correct string contents. I would test this by simply splitting the printing code from the string-generating code, then only test the generating code while assuming that the basic Rust functionality of printing to stdout works fine. E.g. impl Foo { fn make_hello() -> String { String::from("Hello, World!") } pub fn print_hello() { let line = make_hello(); println!("{line}"); } } Now you can write all the tests for `make_hello()` that you require by examining the returned string, without needing any abstracted IO traits.