Skip to content

Commit

Permalink
Using assert_fs, predicates, and assert_cmd to integration test bins …
Browse files Browse the repository at this point in the history
…that spawn subcommands

How to integration test a cargo binary that calls
out to `EDITOR` for modifications and asks the
user for input.

First we'll create a fake editor script to use
instead of vim, etc.

`tests/fake_editor.sh` is a one-liner.

```shell
echo "testing" >> $1;
```

Then we'll write our test using `assert_cmd` to
build up a `Command` that points to the `garden`
binary in out `Cargo.toml`.

We grab the fake editor path script using
`std::env::current_dir()`, make sure the file
exists (which means we've grabbed the right
path), and spawn a new `Command` with the
`EDITOR` variable set to the fake editor
script. The equivalent call to our bin is

```shell
EDITOR=path/to/fake-editor.sh garden write -t atitle
```

And the rust code to execute.

```rust
fn test_write_with_title() {
    let mut cmd = Command::cargo_bin("garden").unwrap();
    let fake_editor_path = std::env::current_dir()
        .expect("expect to be in a dir")
        .join("tests")
        .join("fake-editor.sh");
    if !fake_editor_path.exists() {
        panic!(
            "fake editor shell script could not be found"
        )
    }

    let assert = cmd
        .env("EDITOR", fake_editor_path.into_os_string())
        .arg("write")
        .arg("-t")
        .arg("atitle")
        .write_stdin("N\n".as_bytes())
        .assert();

    assert.success();
}
```

Note that we're asserting that the command
exited sucessfully, and that we're inputing
`N\n` to the bin's stdin, which responds to
a request for user input after the editor
closes.

Note that this doesn't actually test for
the resulting file existence, and also that
we're writing our files out directly into
our default digital garden! We can solve
this with `assert_fs` and `predicates`.

We'll bring in both preludes (a prelude is
a bunch of stuff the library author thinks
will be useful to have around all the time)
and create a new temporary directory.

We'll use the `GARDEN_PATH` environment
variable to pass the temporary directory in
to the `garden` bin and that's it, we've
added a temporary directory to our test.
No more polluting the default garden!

```rust
use assert_fs::prelude::*;
use predicates::prelude::*;

fn test_write_with_title() {
    let temp_dir = assert_fs::TempDir::new().unwrap();

    let mut cmd = Command::cargo_bin("garden").unwrap();
    let fake_editor_path = std::env::current_dir()
        .expect("expect to be in a dir")
        .join("tests")
        .join("fake-editor.sh");
    if !fake_editor_path.exists() {
        panic!(
            "fake editor shell script could not be found"
        )
    }

    let assert = cmd
        .env("EDITOR", fake_editor_path.into_os_string())
        .env("GARDEN_PATH", temp_dir.path())
        .arg("write")
        .arg("-t")
        .arg("atitle")
        .write_stdin("N\n".as_bytes())
        .assert();

    assert.success();

    temp_dir
        .child("atitle.md")
        .assert(predicate::path::exists());
}
```

Now that's enough, but we can also check
to make sure the file we expect to exist
actually exists. `temp_dir.child` gives
us the possible file, and we can assert
on that file with a test from `predicates`
that tests to make sure the file exists.

```rust
temp_dir
    .child("atitle.md")
    .assert(predicate::path::exists());
```
  • Loading branch information
ChristopherBiscardi committed Jan 16, 2021
1 parent 5cf2467 commit dccfede
Show file tree
Hide file tree
Showing 4 changed files with 192 additions and 4 deletions.
161 changes: 161 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions Cargo.toml
Expand Up @@ -23,3 +23,5 @@ structopt = "0.3.21"

[dev-dependencies]
assert_cmd = "1.0.2"
assert_fs = "1.0.0"
predicates = "1.0.6"
1 change: 1 addition & 0 deletions tests/fake-editor.sh
@@ -0,0 +1 @@
echo "testing" >> $1;
32 changes: 28 additions & 4 deletions tests/integration.rs
@@ -1,5 +1,7 @@
use assert_cmd::Command;
use assert_fs::prelude::*;
use color_eyre::eyre::Result;
use predicates::prelude::*;

#[test]
/// make sure help runs. This indicates the binary works
Expand All @@ -20,10 +22,32 @@ fn test_write_help() -> Result<()> {
}

#[test]
#[ignore]
/// execute the write command, saving a file out.
fn test_write() {
fn test_write_with_title() {
let temp_dir = assert_fs::TempDir::new().unwrap();

let mut cmd = Command::cargo_bin("garden").unwrap();
let assert = cmd.arg("write").assert();
let fake_editor_path = std::env::current_dir()
.expect("expect to be in a dir")
.join("tests")
.join("fake-editor.sh");
if !fake_editor_path.exists() {
panic!(
"fake editor shell script could not be found"
)
}

let assert = cmd
.env("EDITOR", fake_editor_path.into_os_string())
.env("GARDEN_PATH", temp_dir.path())
.arg("write")
.arg("-t")
.arg("atitle")
.write_stdin("N\n".as_bytes())
.assert();

assert.success();

temp_dir
.child("atitle.md")
.assert(predicate::path::exists());
}

0 comments on commit dccfede

Please sign in to comment.