Testing Enums within matches

Hi

Perhaps I'm thinking about testing wrong here? But I'm trying to write a couple of tests on an Enum for my CLI. One is a valid action and one is invalid. I have a impl frm_Str() method which uses a match to confirm that the passed in action is valid, if valid it returns the type of enum. If it fails it returns Err(format!("Unknown action: {}", e)).

These are my tests:

#[cfg(test)]
mod test {
    use super::*;

    #[test]
    fn valid_action() {

        let action : ActionKind = "gray".parse().unwrap();
        assert_eq!( action, ActionKind::Gray );
    }

    #[test]
    fn invalid_action() {

        let invalid : ActionKind = "invalid".parse().unwrap();
        assert_eq!( invalid, Err );
    }
}

The enum and impl is:

#[derive(Debug, PartialEq)]
pub enum ActionKind {
    Gray,
    Thumb,
    Rotate,
    Crop
}

impl FromStr for ActionKind {
    type Err = String;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s {
            "gray" => Ok(ActionKind::Gray),
            "thumb" => Ok(ActionKind::Thumb),
            "rotate" => Ok(ActionKind::Rotate),
            "crop" => Ok(ActionKind::Crop),
            e @ _ => Err(format!("Unknown action: {}", e)),
        }
    }
} 

So, am I testing things that don't need to be tested here? :confused: and if I'm not, how should I write a test to confirm that the commands are handled properly? (i.e if it's valid it returns the Enum, if invalid it Err)

Is your concern here that the above test doesn't compile? The problem is the

assert_eq!( invalid, Err );

line, which is a syntax error. If you want to compare with a value, then you need to use something like this:

#[test]
fn invalid_action() {
    let invalid: Result<ActionKind, _> = "invalid".parse();
    let msg = String::from("Unknown action: invalid");
    assert_eq!(invalid, Err(msg));
}

Note that I've changed two things:

  1. I've removed the call to unwrap since the parsing fails and unwrap would thus start a panic.
  2. I've replaced Err with a proper error value: Err by itself it not a value, you must use it with a string to get a value.

If you don't want to check the precise error message, then you could use

#[test]
fn invalid_action() {
    let invalid: Result<ActionKind, _> = "invalid".parse();
    assert!(invalid.is_err());
}

instead.

With those changes, I think your tests are fine: the type checking will ensure that your parse method returns a proper Result<ActionKind, String>, but the tests are still needed to ensure that the function implements the correct logic, e.g., that is parses "crop" and not "invalid".

1 Like

Thanks, that did work for me and I have been unsure when dealing with more complex types the best way to test these kind of scenarios. :slight_smile: