Thong Nguyen
Thong Nguyen

Reputation: 291

How to write tests for command line tool built with structopt

So I built a small Rust CLI tool with structopt and now want to add some tests but didn't find any useful docs/ examples about how to write it

use structopt::StructOpt;


#[derive(Debug, StructOpt)]
#[structopt(name = "example")]
struct Cli {
    domain: String,
}

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let args = Cli::from_args();

    let url = format!("https://example.com/{}", args.domain);
    let resp = ureq::get(&url.to_string()).call().into_json()?;

    println!("Has data for domain: {}", args.domain);
    Ok(())
}

I'm about to have tests something like this

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

    #[test]
    fn valid_domain() {
        // Example functions
        let cli = Cli::build_command(domain: "google.com");
        let output = cli.run_command();

        assert!(output.contains("Has data"));
    }
}

I now can resolve my issue with assert_cmd crate, some of my tests

mod tests {
    use assert_cmd::Command;

    #[test]
    fn valid_domain() {
        let mut cmd = Command::cargo_bin("example").unwrap();
        let output = cmd.arg("google.com").unwrap();
        let output_str = String::from_utf8(output.stdout).unwrap();
        assert!(output_str.contains("Has data"));
    }

    #[test]
    #[should_panic(expected = "Invalid domain")]
    fn invalid_domain() {
        Command::cargo_bin("example").unwrap().arg("google").unwrap();
    }
}

Upvotes: 0

Views: 142

Answers (1)

cafce25
cafce25

Reputation: 27538

You can invoke the parser with Cli::from_iter(["yourbinary", "your", "arguments"]) but after that you're on your own since structopt only provides commandline parsing.

It's probably best to split main into testable functions/methods, if you go by your wish API something like

impl Cli {
    fn run_command(&self) -> String {
        todo!() // your business logic
    }
}

and use that in the tests and in main instead of the code you currently have.

Upvotes: 2

Related Questions