For this post, I would like to talk about testing yassgy (and how difficult it is…).
I have implement very small test cases on a very small part of
yassgy currently is untestable, and I noticed that refactoring it would a major task, I decided to focus on a really small function of
yassgy, testing whether a file path refers to a text file.
I used the built-in testing features included in
cargo, by using the
cfg attribute and prefixing my test functions with the
For example, let us say we have a file called
complex.rs, that defines a structure for a complex number:
#[derive(Debug, Eq)] struct Complex real: f64, imaginary: f64 impl Complex fn add(self, rhs: Complex) -> Complex Complex real: self.real + rhs.real, imaginary: self.imaginary + rhs.imaginary, impl Add for Complex type Output = Self; fn add(self, other: Self) -> Self self.add(other)
If I wanted to test this structure, I can simply write the following in the same file:
struct Complex // snip #[cfg(test)] mod tests use super::*; #[test] fn add_two_complex_numbers() let a = Complex real: 1.0, imaginary: 1.0 ; let b = Complex real: 1.5, imaginary: 2.3 ; let expected = Complex real: 2.5, imaginary: 3.3 ; assert_eq!(a + b, expected);
And thus, we have implemented the first test case!
This test case can be easily run in the command line with
We can also implement a second test case, where we test the subtraction of two complex numbers, and, because we are not supporting a
Sub operation, the test case would fail!
The test cases for
yassgy were pretty simple, focused on the function that tests whether a file path refers to a text file.
Writing a few test cases helped me to realize test cases define a specification of your program, and they count in some way as documentation of your program. Thus, testing provide several benefits that outweigh the maintenance costs of the code.