如何为使用structopt构建的命令行工具编写测试。

huangapple go评论49阅读模式
英文:

How to write tests for command line tool built with structopt

问题

以下是您要求的翻译:

所以我用 `structopt` 构建了一个小型的 Rust 命令行工具,现在想添加一些测试,但未找到任何有用的文档或示例来编写它。

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(())
}
我即将编写类似于以下的测试

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

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

        assert!(output.contains("Has data"));
    }
}
现在我可以使用 [assert_cmd][1] crate 解决我的问题,以下是一些我的测试

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();
    }
}

[1]: https://docs.rs/assert_cmd/latest/assert_cmd/
英文:

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 = &quot;example&quot;)]
struct Cli {
    domain: String,
}

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

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

    println!(&quot;Has data for domain: {}&quot;, 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: &quot;google.com&quot;);
        let output = cli.run_command();

        assert!(output.contains(&quot;Has data&quot;));
    }
}

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(&quot;example&quot;).unwrap();
        let output = cmd.arg(&quot;google.com&quot;).unwrap();
        let output_str = String::from_utf8(output.stdout).unwrap();
        assert!(output_str.contains(&quot;Has data&quot;));
    }

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

答案1

得分: 2

你可以使用Cli::from_iter(["yourbinary", "your", "arguments"])来调用解析器,但在那之后,你需要自己处理,因为structopt仅提供命令行解析。

最好将main拆分为可测试的函数/方法,如果你按照你的API愿望,可以像这样做:

impl Cli {
    fn run_command(&self) -> String {
        todo!() // 你的业务逻辑
    }
}

然后在测试和main中使用它,而不是当前的代码。

英文:

You can invoke the parser with Cli::from_iter([&quot;yourbinary&quot;, &quot;your&quot;, &quot;arguments&quot;]) 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(&amp;self) -&gt; String {
        todo!() // your business logic
    }
}

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

huangapple
  • 本文由 发表于 2023年7月13日 22:43:30
  • 转载请务必保留本文链接:https://go.coder-hub.com/76680677.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定