DEV Community

Cover image for Using Trait for Unit testing in Rust
Ahmad Rosid
Ahmad Rosid

Posted on

Using Trait for Unit testing in Rust

Trait is one of powerful feature in rust. If you are coming from object oriented world, the Trait is like interface.

On of example of how we can use trait is to define abstraction for writing file. Let's create some trait code.

pub trait Buffer {
    fn write(&mut self, data: &str);
}
Enter fullscreen mode Exit fullscreen mode

So these buffer we will use to be an abstraction to write file.

Next, let's create BufferWritter struct for the actual implementation to the Buffer trait.

pub struct BufferWriter {
    writer: BufWriter<File>,
}

impl BufferWriter {
    pub fn new(file: File) -> Self {
        let writer = BufWriter::new(file);
        Self { writer }
    }
}
Enter fullscreen mode Exit fullscreen mode

And now let's implement our trait to BufferWritter.

impl Buffer for BufferWriter {
    fn write(&mut self, data: &str) {
        let bytes = format!("{}\n", data).as_bytes();
        if let Err(e) = self.writer.write_all(bytes) {
            println!("Failed to write data to file: {}", e);
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

And now let's use it to write file, first let's suppose we have some logic that made some text processing and turn it to some generated code.

pub fn write_output(buffer: Box<dyn Buffer>, config: &Config, source: &HashSet<String>) {
    let mut generator = Parser::new(buffer, config.clone());
    for line in source.iter() {
        if generator.plugin(line).is_some() {
            continue;
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

And here's our parser.

pub struct Parser {
    config: Config,
    writer: Box<dyn Buffer>,
}

impl Parser {
    pub fn new(writer: Box<dyn Buffer>, config: Config) -> Self {
        Self { config, writer }
    }
    pub fn plugin(&self, line: &str) {
        // Some processing and then
        self.writter.write(some_str);
    }
}
Enter fullscreen mode Exit fullscreen mode

Testing

One of the advantage of trait is for testing. In this case, we don't want to work with file directly whenever we are doing testing.

So let's take a look how we can use trait for testing.

#[test]
fn test_columns() {
    let config_set = Parser::parse(include_str!("source.json")).unwrap();
    let test_case = vec![
        ("name", "my-name"),
        ("wrong", "not-wrong"),
    ];

    struct Buf(String);
    impl Buffer for Buf {
        fn write(&mut self, data: &str) {
            assert_eq!(data, self.0)
        }
    }

    for (class, expected) in test_case {
        write_output(Box::new(Buf(expected.into())), &config_set, &set![class]);
    }
}
Enter fullscreen mode Exit fullscreen mode

So that it for now, if you want to read more about rust tutorial follow me at twitter @_ahmadrosid and don't forget to visit my blog ahmadrosid.com

Thank you let me know if you have any question.

Top comments (0)