使用
clap
为 CLI 程序编写测试的最惯用方法是什么?我目前正在这样做:
#[derive(Debug, Parser)]
#[clap(author, version, about)]
pub struct StructArgs {
#[clap(subcommand)]
pub command_type: CommandType,
}
#[derive(Debug, Subcommand)]
pub enum CommandType {
Command1(Command1Args),
...
}
#[derive(Debug, Args)]
pub struct Command1Args {
pub field: String,
...
}
impl Command1Args {
...
}
#[test]
fn test_do_stuff() {
let args = StructArgs::try_parse_from(
std::iter::once("<PROGRAM NAME>")
.chain(
["<ARG 1>", ..., "<ARG n>"]
.iter()
.cloned()
)
);
if let CommandType::Command1(command1_args) = args.command_type {
// do stuff with command1_args
} else {
panic!();
}
}
基本上,我传递给
clap
一个参数迭代器,然后检查解析的命令结构是否与我期望的 CommandType
匹配,然后继续测试其方法和内部状态。 else 分支中的 panic
表示如果由于某种原因我得到意外的 CommandType
,则测试失败,这意味着很可能我在迭代器中写了错误的内容。
这个可以进一步改进吗?
Chayim 说你不应该测试 Clap 确实有道理。但在某些情况下情况并非如此,为使用 clap 实现的 CLI 解析器编写单元测试确实有意义。
就我而言,我想定义一组参数,仅当设置了某个标志时才需要这些参数,如果设置了,则需要该组的所有参数。在 Clap 中定义这并不是一件小事,测试它是有意义的,例如像这样(使用 Clap 4.4):
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn oidc_all_or_nothing() {
/* Call it without any OIDC args, just graqphiql; must work */
if let Err(err) = AppConfig::try_parse_from(vec!["aisrv", "--enable-graphiql"].iter()) {
panic!("Just --enable-graphiql failed: {err}");
}
/* Call with only one OIDC arg, must fail */
if AppConfig::try_parse_from(vec!["aisrv", "--oidc-idp-url", "tescht"].iter()).is_ok() {
panic!("Just one OIDC arg did not fail!");
}
/* Call with all OIDC args, must succeed */
if let Err(err) = AppConfig::try_parse_from(
vec![
"aisrv",
"--oidc-idp-url",
"tescht",
"--oidc-super-admin-user",
"tescht",
"--oidc-super-admin-password",
"tescht",
"--oidc-super-admin-client-id",
"tescht",
"--oidc-super-admin-client-secret",
"tescht",
"--oidc-aud",
"tescht",
]
.iter(),
) {
panic!("All OIDC args passed, but still fails: {err}");
}
}
}