2016-03-25 23 views
5

我进入legacy shell脚本的unit testingShell脚本单元测试:如何模拟复杂的应用程序

在现实世界中的脚本通常被用来调用实用程序 像findtarcpiogrepsedrsyncdate等含有很多选择一些比较复杂的命令行。有时会构造和使用正则表达式或通配符模式。

例如:这通常是由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 
     ... 
    } 
    ... 

正如迈克尔羽毛在他的名著Working Effectively with Legacy Code写道,良好的单元测试的运行速度非常快,不接触网络,文件 - : 几个类型的文件和目录应该从 镜像过程中被排除在外系统或打开任何数据库。

继迈克尔羽毛建议这里使用的技术是:dependency injection。这里要替换的对象是应用程序rsync

我最初的想法:在我的shell脚本测试框架(我用bats)我操纵$PATH的方式,一个mockuprsync被发现的,而不是 真正rsync效用。这个mockup对象可以检查提供的命令行参数和选项。与script under test的这部分中使用的其他实用程序类似。

我以前在脚本编写领域遇到的实际问题经验往往是由文件或目录名称中的特殊字符,引用或编码问题,缺少ssh密钥,错误权限等引起的错误。这些类型的错误将会逃脱这种单元测试技术。 (我知道:对于这些问题中的一些问题,单元测试根本不是治愈方法)。

另一个缺点是为rsyncfind等复杂实用程序编写mockup容易出错并且是一项单调乏味的工程任务。

我相信上面描述的情况已经足够普遍,其他人可能会遇到类似的问题。谁有一些聪明的想法,并且会在意与我分享这些想法?

+3

单元测试后,需要系统测试。也许建立一个简单的测试网络,其中包含每个有问题的文件,目录,缺失的密钥等。 – tripleee

+1

使用与实际场景内联的“tee”来捕获被调用的命令响应,然后使用这些文件在测试利用场景中播放,也许用一个记录收到的参数的脚本,并盲目地发送罐装响应。 –

+0

@Keith Tyler:这是一个非常整洁的想法:很显然,这种技术需要事先编写一些系统测试(但是当开始摆弄旧版脚本时,在开始重构脚本之前至少编写一些这样的测试无论如何都是一件好事理念)。赞成这个建议。 – pefu

回答

1

嘉吉的窘境:

“任何设计问题可以通过添加额外的间接水平,除了间接的层次太多自己解决。”

为什么模拟系统命令?毕竟,如果你编程Bash,系统是你的目标,你应该使用系统来评估你的脚本。

顾名思义,单元测试会让你对你正在设计的系统单一部分有信心。所以你必须定义什么是你的单元在bash脚本的情况下。一个函数?脚本文件?一个命令?

给你想要的单元定义为功能那么我会建议写众所周知错误的列表,你上面列出:

  • 文件或目录名
  • 问题有特殊字符引用或编码
  • 缺少ssh密钥
  • 错误的权限等等。

然后为它写一个测试用例。并尽量不要偏离系统命令,因为它们是积分您正在交付的系统的一部分。

0

可以使用的功能,这样的实体模型的任何命令:

function rsync() { 
    # mock things here if necessary 
} 

然后导出功能和运行单元测试:

export -f rsync 
unittest