Struggling to test file system IO methods bounded to structs

I'm afraid this is a very newbie question, but I've been fighting the compiler for too long, so I've come here to ask for help :-). I've simplified my scenario to capture only what I'm stuck with.

Say I have a struct:

pub struct Worker{
    id: u32,
    filename: String,
}

This struct has a method to handle writes to the file system (along with its constructor):

impl Worker {
    pub fn new(
        id: u32,
        filename: String,
    ) ->  Worker {
        Worker {
            id: id,
            filename: filename,
        }
    }

    pub fn read_file(&self) -> io::Result<String> {
        Ok(fs::read_to_string(&mut Path::new(&self.filename))?)
    }

    pub fn do_task(&self) -> Result<(), MyError> {
        // -- sniip
        let mut new_file = File::create(self.filename).map_err(MyError::Io)?;
        // -- sniip
    }

Say I wanna test do_task() for the case where File::create fails, and I wanna check that the error I got was indeed MyError::Io.

The way I've been trying to do it was to pass a Write trait to my struct (or something like that) so I don't call File::create directly and instead use whatever was passed to Worker::new(...). During my tests I'd pass a mocked version that could trigger the FS error. But I've tried many, many ways of doing that but I can't seem to make it work, all I want is something like passing mut writer: impl std::io::Write to Worker::new(). How would you folks approach this?

Thank you so much in advance!

The Write trait has no create function, and you would have to create your own trait to mock it. I believe the easiest would be to just intentionally trigger a failure by e.g. trying to create a file in a directory that doesn't exist.

1 Like

That's a very good point, I believe I will do that. But here's a follow-up question: I will also want to test that read_file and would like to inject the fs::read_to_string() instead of hardcoding it there. How would be the right approach to do this kind of dependency injection?

Thank you!

I'm not quite sure which of the two suggestions you believe you will do, but how about just creating a file and reading from it?

1 Like