在OOP universum中,有很多关于如何设计和重构代码以使其单元测试友好的information。但我想知道,如何将这些原则/实践(使mocking更容易等)应用/翻译到shell脚本,这显然是不同的编程。
我必须处理一个非常庞大的代码库;许多可执行和不可执行过程、大函数、大全局状态、许多环境变量、以及通过重定向/管道和(不必要的)使用外部实用程序的到处(不必要的)进程间通信和文件处理。
如何重构shell代码(或在开始时设计它),以便能够使用像bats和mocking-plugin这样的框架来进行“好的”自动化单元测试?
3条答案
按热度按时间huwehgph1#
单元测试是为了在孤立的代码中发现错误。然而,典型的shell代码主要是与其他可执行文件或操作系统的交互。shell代码中的交互中存在的问题类型是,我是否以正确的顺序调用正确的可执行文件,参数是否以正确的顺序调用,参数值是否格式正确,要测试所有这些,您不应该应用单元测试,而是应用集成测试。
然而,有一些shell代码适合单元测试。例如,在shell中执行计算或字符串操作的代码。我甚至认为调用某些基本函数类工具(如
basename
)的shell代码适合单元测试(如果你愿意,可以将这些工具解释为“标准库”的一部分)。如何使shell中适合进行单元测试的代码部分实际上可以通过单元测试进行测试?根据我的经验,最有用的方法之一是将交互与计算分离。也就是说,尝试将计算部分放在单独的shell函数中进行测试,或者将交互主导的部分提取到单独的shell函数中。这可以节省大量的模拟工作。
vwkv1x7d2#
问得好!
恕我直言,shellscripts通常只是调用其他程序来完成任务,比如
cp
,mv
,tar
,rsync
,...即使对于表达式bash也使用二进制test
,如果你使用[ and ](例如if [ -f $file ]; then; fi
)。考虑到这一点,想想bash脚本中真正发生的事情:使用三个参数调用该程序。因此,您可以编写一个unit-tests,它检查bash脚本是否调用了所需的程序并使用了正确的参数,并检查程序的返回值/退出代码。
你肯定不想把你的shell脚本放在单元测试中,这是由另一个程序有效地完成的(例如,检查
rsync
是否真的从机器A复制文件到机器B)。只是我的意见
p4tfgftt3#
靶区;DR
下面是一个模板存储库 *,其中包含使用Travis-CI对shell文件进行的持续集成单元测试:https://github.com/a-t-0/shell_unit_testing_template
由于repo可能有一天会消失,这里有一个关于可复制性的想法(注意,这不一定是最好的方法,这只是我发现的一种工作方式)。
文件结构
shell脚本位于
/src/
文件夹中。单元测试位于/test/
文件夹中。在/src/
中,有一个main.sh
可以调用其他shell脚本。其他shell脚本可以由单独的可测试函数组成,例如文件active_function_string_manipulation.sh
。(包括在下面)为了让它工作,我需要安装对
bats
文件的支持,这些文件是单元测试文件。这是用install-bats-libs.sh
文件完成的,内容是:Shell脚本
/src/ is:
active_function_string_manipulation.sh`中的shell脚本示例。单元测试
单元测试由存储库根目录中的一个名为
test.sh
的文件运行。它包含以下内容:一个例子是测试:
active_function_string_manipulation.sh
与:/test/test_active_function_string_manipulation.bats
:Travis CI
Travis CI使用
yml
文件实现,该文件基本上创建了一个环境并在自动化环境中运行测试。该文件名为:.travis.yml
,包含:披露 *
我参与了this repository的构建,它是“for dummies/me”-指令in this article的实现。
注解
我目前对这个系统的扩展能力没有太多的了解,我目前无法估计它是否有潜力成为一个“生产就绪”的系统,或者它是否适合这样的大项目,它仅仅是一个shell代码的自动化单元测试环境。