Вопрос:

Как проверить код выхода из std :: process :: exit () в тестах?

rust

448 просмотра

1 ответ

3377 Репутация автора

В тестах Rust, есть ли способ проверить, что функция, которая вызывает std::process::exit()действительно завершил процесс с определенным кодом выхода?

Придуманный пример:

fn foo(n: i32) {
    std::process::exit(n);
}

#[test]
fn exits_with_correct_exit_code() {
    // How do I assert that the following call terminates
    // the process with exit code 1?
    foo(1);
}
Автор: s3rvac Источник Размещён: 13.04.2017 11:24

Ответы (1)


3 плюса

179375 Репутация автора

Решение

Тебе нельзя. std::process:exitхорошо назван, но на всякий случай неясен аспект того, что он делает:

Завершает текущий процесс с указанным кодом выхода.

Эта функция никогда не вернется и немедленно прекратит текущий процесс. Код выхода передается в базовую ОС и будет доступен для использования другим процессом.

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

При запуске тестов каждый тест выполняется в отдельном потоке , но все тесты выполняются в рамках одного процесса. Когда этот процесс завершается, тесты идут вместе с ним.

Вы можете попробовать сделать несколько сложных рекурсивных тестов:

#[test]
#[ignore]
fn real() {
    std::process::exit(42)
}

#[test]
fn shim() {
    let status = std::process::Command::new("/proc/self/exe")
        .args(&["--ignored", "real"])
        .status()
        .expect("Unable to run program");

    assert_eq!(Some(42), status.code());
}

У этого есть специфичный для платформы код, чтобы найти текущий процесс, но он «работает».


Хотя, честно говоря, я бы сказал, что код выходит за границы тестирования. Вы не должны тестировать то std::process::exit, что говорит. Если вам действительно нужно утверждать, что функция вызывается с аргументом, это то, для чего предназначен фиктивный объект .

Используйте внедрение зависимостей, чтобы обеспечить замыкание, захватить значение в замыкании и написать тонкую прокладку:

fn foo_logic<F>(n: i32, f: F)
    where F: FnOnce(i32)
{
    f(n);
}

fn foo(n: i32) {
    foo_logic(n, |n| std::process::exit(n));
}

#[test]
fn exits_with_correct_exit_code() {
    let mut value = None;
    foo_logic(1, |v| value = Some(v));
    assert_eq!(Some(1), value);
}

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

Автор: Shepmaster Размещён: 13.04.2017 12:53
Вопросы из категории :
32x32