Как проверить, была ли вызвана функция в Rust? - PullRequest
0 голосов
/ 08 февраля 2019

У меня есть функция следующим образом

pub fn registration(student_id: &T::StudentId, registrar: &T::RegistrarID) {
    // More code here.
    if num_of_students < student_limit {
        Self::function_one(&registrar, &num_of_students);
    } else {
        Self::function_two(&num_of_students);
    }
}

В модульных тестах я планирую проверить, был ли вызван function_one или function_two.

#[test]
fn registration_more_students_should_call_functon_one() {
    with_test_data(
        &mut TestBuilder::default().num_of_students(1000).build(),
        || {
            //assert_called!(module_name::registration("TV:009", "DF-000-09"));
        },
    );
}

Как я могупроверить, была ли вызвана функция в Rust?

Ответы [ 2 ]

0 голосов
/ 08 февраля 2019

Предупреждение о сильном мнении: вы неправильно тестируете .Это на том же уровне, что и «как проверить приватный метод».Вам не нужно заботиться о реализации registration до этого уровня детализации.

При этом, если на самом деле важно знать, какая ветвь if взята, то используйте внедрение зависимостей:

fn registration(mut registration: impl Registration, registrar: i32) {
    let num_of_students = 0;
    let student_limit = 0;

    if num_of_students < student_limit {
        registration.function_one(registrar, num_of_students);
    } else {
        registration.function_two(num_of_students);
    }
}

trait Registration {
    fn function_one(&mut self, registrar: i32, num_of_students: i32);
    fn function_two(&mut self, num_of_students: i32);
}

impl<R: Registration> Registration for &'_ mut R {
    fn function_one(&mut self, registrar: i32, num_of_students: i32) {
        (**self).function_one(registrar, num_of_students)
    }
    fn function_two(&mut self, num_of_students: i32) {
        (**self).function_two(num_of_students)
    }
}

/*
// An example implementation for production
struct DatabaseRegistration;

impl Registration for DatabaseRegistration {
    fn function_one(&mut self, registrar: i32, num_of_students: i32) {
        eprintln!("Do DB work: {}, {}", registrar, num_of_students)
    }
    fn function_two(&mut self, num_of_students: i32) {
        eprintln!("Do DB work: {}", num_of_students)
    }
}
*/

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

    #[derive(Debug, Copy, Clone, Default)]
    struct TestRegistration {
        calls_to_one: usize,
        calls_to_two: usize,
    }

    impl Registration for TestRegistration {
        fn function_one(&mut self, _: i32, _: i32) {
            self.calls_to_one += 1;
        }
        fn function_two(&mut self, _: i32) {
            self.calls_to_two += 1;
        }
    }

    #[test]
    fn calls_the_right_one() {
        let mut reg = TestRegistration::default();
        registration(&mut reg, 42);
        assert_eq!(1, reg.calls_to_two)
    }
}

Как только вы это сделаете, вы увидите, что registration вызывает соответствующую функцию черты (как показано в примере теста).

Это предотвращает разбрасывание специфического для теста детрита, а также дает вам возможность быть более гибким и быстрее тестировать больше случаев.

См. Также:

0 голосов
/ 08 февраля 2019

Вот наивная попытка использования #[cfg(test)] в нескольких местах:

struct Registration {
    students: Vec<String>,
    #[cfg(test)]
    function_1_called: bool,
}

impl Registration {
    fn new() -> Self {
        Registration {
            students: Vec::new(),
            #[cfg(test)]
            function_1_called: false,
        }
    }

    fn function_1(&mut self, students: Vec<String>) {
        self.students.extend(students);
        #[cfg(test)]
        {
            self.function_1_called = true;
        }
    }

    fn function_2(&mut self, students: Vec<String>) {}

    fn f(&mut self, students: Vec<String>) {
        if students.len() < 100 {
            self.function_1(students);
        } else {
            self.function_2(students);
        }
    }
}

fn main() {
    println!("Hello, world!");
    let r = Registration::new();
    // won't compile during `run`:
    // println!("{}", r.function_1_called);
}

#[cfg(test)]
mod test {
    use super::*;
    #[test]
    fn test_f() {
        let mut r = Registration::new();
        r.function_1(vec!["Alice".to_string(), "Bob".to_string()]);
        assert!(r.function_1_called);
    }
}

Код основан на предоставленных вами фрагментах кода.Существует структура Registration, которая содержит список имен учеников, два метода function_1 и function_2 для регистрации учеников и функция f, которая выбирает между function_1 и function_2 в зависимости от количества учеников.are.

Во время тестов Registration компилируется с дополнительной логической переменной function_1_called.Эта переменная устанавливается, только если вызывается function_1 (блок кода, который делает это, также помечается #[cfg(test)]).

В комбинации это делает дополнительный логический флаг доступным во время тестов, так чтоВы можете сделать утверждения, подобные следующему:

assert!(r.function_1_called);

Очевидно, что это может работать для структур, намного более сложных, чем один логический флаг (что вовсе не означает, что вы должны это делать).

Я не могу комментировать, является ли это идиоматическим в Rust или нет.Вся установка выглядит так, как будто она должна быть скрыта за причудливыми макросами, поэтому, если этот стиль тестирования вообще используется в Rust, уже должны быть ящики, которые предоставляют эти (или подобные) макросы.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...