Communities

Writing
Writing
Codidact Meta
Codidact Meta
The Great Outdoors
The Great Outdoors
Photography & Video
Photography & Video
Scientific Speculation
Scientific Speculation
Cooking
Cooking
Electrical Engineering
Electrical Engineering
Judaism
Judaism
Languages & Linguistics
Languages & Linguistics
Software Development
Software Development
Mathematics
Mathematics
Christianity
Christianity
Code Golf
Code Golf
Music
Music
Physics
Physics
Linux Systems
Linux Systems
Power Users
Power Users
Tabletop RPGs
Tabletop RPGs
Community Proposals
Community Proposals
tag:snake search within a tag
answers:0 unanswered questions
user:xxxx search by author id
score:0.5 posts with 0.5+ score
"snake oil" exact phrase
votes:4 posts with 4+ votes
created:<1w created < 1 week ago
post_type:xxxx type of post
Search help
Notifications
Mark all as read See all your notifications »
Code Reviews

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

75%
+4 −0
Code Reviews Writing a testable console program

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...

posted 11mo ago by deleted user  ·  edited 11mo ago by deleted user

Answer
#4: Post edited by (deleted user) · 2023-05-23T13:56:51Z (11 months ago)
Add mention of standard trait
  • > 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 by (deleted user) · 2023-05-23T09:39:01Z (11 months ago)
Discuss method visibility
  • > 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 by (deleted user) · 2023-05-23T09:33:26Z (11 months ago)
Add comments about test organisation
  • > 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 by (deleted user) · 2023-05-23T09:23:40Z (11 months ago)
 > 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.