在现实世界中,脚本通常用于调用实用程序,如find
、tar
、cpio
、grep
、sed
、等rsync
,date
其中包含一些包含很多选项的相当复杂的命令行。有时会构造和使用正则表达式或通配符模式。
一个例子:通常由 cron 定期调用的 shell 脚本的任务是使用实用程序rsync将一些巨大的目录树从一台计算机镜像到另一台计算机。应该从镜像过程中排除几种类型的文件和目录:
#!/usr/bin/env bash
...
function mirror() {
...
COMMAND="rsync -aH$VERBOSE$DRY $PROGRESS $DELETE $OTHER_OPTIONS \
$EXCLUDE_OPTIONS $SOURCE_HOST:$DIRECTORY $TARGET"
...
if eval $COMMAND
then ...
else ...
fi
...
}
...
正如 Michael Feathers 在他著名的著作《有效地使用遗留代码》中所写,一个好的单元测试运行速度非常快,并且不会触及网络、文件系统或打开任何数据库。
按照 Michael Feathers 的建议,这里使用的技术是:依赖注入。这里要替换的对象是实用程序rsync
。
我的第一个想法:在我的 shell 脚本测试框架(我使用bats)中,我$PATH
以找到模型 rsync
而不是真正的rsync
实用程序的方式进行操作。这个模型对象可以检查提供的命令行参数和选项。与被测脚本的这一部分中使用的其他实用程序类似。
我过去在脚本编写领域遇到的实际问题通常是由文件或目录名称中的特殊字符、引用或编码问题、缺少 ssh 密钥、错误权限等引起的错误。这种类型的错误将逃脱这种单元测试技术。(我知道:对于其中一些问题,单元测试根本无法解决问题)。
另一个缺点是为像or这样的复杂实用程序编写模型容易出错,并且本身就是一项繁琐的工程任务。rsync
find
我相信上面描述的情况很普遍,其他人可能也遇到过类似的问题。谁有一些聪明的想法并愿意在这里与我分享?