We have been ignoring implementing tests for the write subcommand. Now is the time that we'll test the command we have been building.
We'll build out a fake editor script that our test will use to check if the command is functioning properly. We will then use arg
to build the command as we would normally use it ourselves.
After writing the test, we'll see how to clean up after ourselves so that we aren't leaving testing artifacts leftover just from running a test.
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.
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
EDITOR=path/to/fake-editor.sh garden write -t atitle
And the rust code to execute.
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!
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.
temp_dir
.child("atitle.md")
.assert(predicate::path::exists());
Note that if you are on Linux, fake-editor.sh
will require the use of a shebang resulting in a file that looks like this:
#!/usr/bin/env bash
echo "testing" >> $1;