Search code examples
rustintegration-testing

How can I get command stdout from a process using assert_cli crate?


I am using assert_cli crate to test a command line application. While it is very helpful with simple use cases (see some examples in this article), sometimes I want to get the raw output of the command I am testing as a String to do more sophisticated checks (regex, json or just more complex logic in the output).

For that I need to get a copy of the command output verbatim. Here is an example:

extern crate assert_cli;

fn main() {
    let a = assert_cli::Assert::command(&["echo", "foo-bar-foo"]);
    a.execute();
    println!("{:?}", a.expect_output);
}

Somewhat predictably it gives me the following error:

error[E0616]: field `expect_output` of struct `assert_cli::Assert` is private
  --> src/main.rs:14:22
   |
14 |     println!("{:?}", a.expect_output);
   |                      ^^^^^^^^^^^^^^^

It also has a .stdout() method, but that requires OutputAssertionBuilder and there it is also not obvious how to access the actual contents of stdout. You can only do some simple checks using predicates syntax.

assert_cli does internally get the full output of the command during execute as seen in the source code of assert.rs

let output = spawned.wait_with_output()?;

All the internal Command and output variables seem to be private and are never exposed to retrieve the raw stdout. This functionality seems to be too basic to be omitted from assert_cli library. I am probably missing something very obvious...

Q: Is there any way to get raw stdout back as contents of a variable?

This is what I want to achieve ideally:

extern crate assert_cli;

fn main() {
    // do simple checkign with assert_cli
    let a = assert_cli::Assert::command(&["echo", "foo-bar-foo"])
        .stdout().contains("foo-bar-foo")
        .unwrap();

    // get raw stdout
    let cmd_stdout = a.get_raw_stdout(); // how to do it?

    // do some additional complex checking
    assert_eq!(cmd_stdout, "foo-bar-foo");
}

P.S.: I know I can use std::process::Command separately to achieve this. I wonder if I can still stick to assert_cli since I do 80% of the testing with it.


Solution

  • The library defines only 3 types. None of which allow to access the output directly.

    This functionality seems to be too basic to be omitted from assert_cli library. I am probably missing something very obvious...

    The library is called assert* and it has all the functions you need to assert stuffs on the output of your command. Getting the actual output is outside the domain of "assertions".

    Other people have opened an issue on the repository asking for this exact feature. I suggest you to go there, and tell the author that this feature interests you.