Best-Practices for Handling Dynamic Errors in Test Code

Hello All,

I'm trying to understand how to properly build unit tests for my object functions which take the form:

fn moc_fn(&self) -> Result<String, Box<dyn Error>>{...}

For this example, all i'm trying to do is import data from a CSV, and propigate any errors through the usage of ?

This is the best test I could write to ensure i caught the error properly:

fn load_from_csv_fail_test(){
    let mut test_task_list = TaskList { tasks: vec![]};
    let error = test_task_list.load_tasks("bad_file").unwrap();

This function passes, but only because it panics on line 5 when we try to unwrap on something that I know returns an error.

Any attempt I make at using assert! claims that a dyn Error can't be known at runtime, making it impossible to check against either the direct error type, nor the string within the object.

Is this the sign that I just need to create my own custom error, and make all my functions return THAT instead of Box<dyn<Error>>? or am I just mis-understanding how dyn Error works and there is some easy way for me to ensure i am getting the RIGHT error within unit tests?

Thanks for your time and patience.

Instead of to #[should_panic], you can .unwrap_err() to get Box<dyn Error> and .downcast() it into your direct error type.

I was trying that approach, can you explain what downcasting does? is it the ability to turn a dyn Error into the proper error type?

From what i'm reading, I would need to implement the Any dynamic trait on the relevant struct to get this downcasting ability?

It feels like Rust is trying to tell me that using the Box paradigm is simply a bad idea, but i've seen it used so commonly that I thought it was standard-practice.

Ah sorry, I posted the wrong link. Similar to the Box<dyn Any> the Box<dyn Error> has a set of downcast methods. I updated the link, please retry it.

1 Like

I've been looking at downcasting for the past few hours,

This is my new formula for trying to pull the io error out:

fn load_from_csv_fail_test(){
    let mut test_task_list = TaskList {task: vec![]};
    let error = test_task_list.load_tasks("bad_file".unwrap)_err();
    let error = error.downcast_ref::<std::io::Error>().unwrap();
    assert!(error.kind() == std::io::ErrorKind::NotFound);

it returns an error saying that unwrap panicked after finding None, but i know that this should return an error.

Thanks for your patience, i'm just trying to build something that could potentially be used as a library.