Использование assert в ветке ошибок при выполнении грузового теста

#rust

#Ржавчина

Вопрос:

Я читаю книгу Rust и работаю над частью minigrep, где он просит вас написать несколько модульных тестов для Config::new функции. Я терплю неудачу в том, чего не ожидал, и не понимаю, почему (Google-fu также подводит меня).

Это не удается

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

    #[test]
    fn it_can_create_a_new_config() {
        let expected_query = "expected_qury";
        let expected_filename = "expected_filename.txt";
        let args: Vec<String> = vec!["program/path".to_string(), expected_query.to_string(), expected_filename.to_string()];

        // failing line
        let actual = Config::new(amp;args).unwrap_or_else(|err| { assert!(false); });
    }
}

impl Config {
    pub fn new(args: amp;[String]) -> Result<Config, amp;'static str> {
        if args.len() < 3 {
            return Err("not enough argumentsn");
        }
    
        let query = args[1].clone();
        let filename = args[2].clone();
     
        Ok(Config { query, filename })
    }
}
 

с

 error[E0308]: mismatched types
  --> src/lib.rs:19:62
   |
19 |         let actual = Config::new(amp;args).unwrap_or_else(|err| { assert!(false); });
   |                                                              ^^^^^^^^^^^^^^^^^^^ expected struct `Config`, found `()`
 

В этом тесте я просто удостоверяюсь, что могу создать новое Config и хочу, чтобы оно завершилось с ошибкой, если Config::new функция завершится с ошибкой. Я думал, что использование assert будет правильным, чтобы тестовая среда обработала сбой. Если я изменю значение assert на panic , тесты пройдут, как и ожидалось. Правильно ли использовать panic в приведенном выше сценарии?

Комментарии:

1. Вы также можете вернуть a Result в тестах: doc.rust-lang.org/edition-guide/rust-2018 /… Это позволило бы вам писать let actual = Config::new(amp;args)?; вместо этого.

Ответ №1:

Проблема в том, что во время проверки типов компилятор (пока) не понимает, что assert!(false) это всегда приведет к сбою, поэтому он должен предположить, что он может пройти, что приведет к значению type () , которое несовместимо с ожидаемым Config типом.

И наоборот, если вы заменяете assert вызовом to panic , компилятор знает, что panic это никогда не возвращается, поэтому не имеет значения, есть ли нет Config возврата. (Строго говоря, panic typechecks возвращает значение type ! , иначе тип «never», который совместим со всем).

IMO вы никогда не должны использовать assert!(false) , а вместо этого использовать panic , когда знаете, что условие всегда фатально. Это делает ваше намерение более понятным.

Хотя в этом конкретном случае, вероятно, было бы лучше утверждать, что результат Ok :

 assert!(Config::new(amp;args).is_ok());
 

Комментарии:

1. Примечание: ожидаемый тип вывода — это Config , а не a Result .

2. Хорошо, я думаю, что понимаю. Я все еще новичок в Rust, некоторые из упомянутых мной вещей — это магия, но в конце концов я научусь этому.