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

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

How to write tests for command line tool built with structopt

问题

以下是您要求的翻译:

  1. 所以我用 `structopt` 构建了一个小型的 Rust 命令行工具,现在想添加一些测试,但未找到任何有用的文档或示例来编写它。
  2. use structopt::StructOpt;
  3. #[derive(Debug, StructOpt)]
  4. #[structopt(name = "example")]
  5. struct Cli {
  6. domain: String,
  7. }
  8. fn main() -> Result<(), Box<dyn std::error::Error>> {
  9. let args = Cli::from_args();
  10. let url = format!("https://example.com/{}", args.domain);
  11. let resp = ureq::get(&url.to_string()).call().into_json()?;
  12. println!("Has data for domain: {}", args.domain);
  13. Ok(())
  14. }
  1. 我即将编写类似于以下的测试
  2. #[cfg(test)]
  3. mod tests {
  4. use super::*;
  5. #[test]
  6. fn valid_domain() {
  7. // 示例函数
  8. let cli = Cli::build_command(domain: "google.com");
  9. let output = cli.run_command();
  10. assert!(output.contains("Has data"));
  11. }
  12. }
  1. 现在我可以使用 [assert_cmd][1] crate 解决我的问题,以下是一些我的测试
  2. mod tests {
  3. use assert_cmd::Command;
  4. #[test]
  5. fn valid_domain() {
  6. let mut cmd = Command::cargo_bin("example").unwrap();
  7. let output = cmd.arg("google.com").unwrap();
  8. let output_str = String::from_utf8(output.stdout).unwrap();
  9. assert!(output_str.contains("Has data"));
  10. }
  11. #[test]
  12. #[should_panic(expected = "Invalid domain")]
  13. fn invalid_domain() {
  14. Command::cargo_bin("example").unwrap().arg("google").unwrap();
  15. }
  16. }
  17. [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

  1. use structopt::StructOpt;
  2. #[derive(Debug, StructOpt)]
  3. #[structopt(name = &quot;example&quot;)]
  4. struct Cli {
  5. domain: String,
  6. }
  7. fn main() -&gt; Result&lt;(), Box&lt;dyn std::error::Error&gt;&gt; {
  8. let args = Cli::from_args();
  9. let url = format!(&quot;https://example.com/{}&quot;, args.domain);
  10. let resp = ureq::get(&amp;url.to_string()).call().into_json()?;
  11. println!(&quot;Has data for domain: {}&quot;, args.domain);
  12. Ok(())
  13. }

I'm about to have tests something like this

  1. #[cfg(test)]
  2. mod tests {
  3. use super::*;
  4. #[test]
  5. fn valid_domain() {
  6. // Example functions
  7. let cli = Cli::build_command(domain: &quot;google.com&quot;);
  8. let output = cli.run_command();
  9. assert!(output.contains(&quot;Has data&quot;));
  10. }
  11. }

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

  1. mod tests {
  2. use assert_cmd::Command;
  3. #[test]
  4. fn valid_domain() {
  5. let mut cmd = Command::cargo_bin(&quot;example&quot;).unwrap();
  6. let output = cmd.arg(&quot;google.com&quot;).unwrap();
  7. let output_str = String::from_utf8(output.stdout).unwrap();
  8. assert!(output_str.contains(&quot;Has data&quot;));
  9. }
  10. #[test]
  11. #[should_panic(expected = &quot;Invalid domain&quot;)]
  12. fn invalid_domain() {
  13. Command::cargo_bin(&quot;example&quot;).unwrap().arg(&quot;google&quot;).unwrap();
  14. }
  15. }

答案1

得分: 2

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

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

  1. impl Cli {
  2. fn run_command(&self) -> String {
  3. todo!() // 你的业务逻辑
  4. }
  5. }

然后在测试和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

  1. impl Cli {
  2. fn run_command(&amp;self) -&gt; String {
  3. todo!() // your business logic
  4. }
  5. }

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:

确定