如何编写可进行单元测试的bash shell代码?

tvz2xvvm  于 2023-03-24  发布在  Shell
关注(0)|答案(3)|浏览(97)

在OOP universum中,有很多关于如何设计和重构代码以使其单元测试友好的information。但我想知道,如何将这些原则/实践(使mocking更容易等)应用/翻译到shell脚本,这显然是不同的编程。
我必须处理一个非常庞大的代码库;许多可执行和不可执行过程、大函数、大全局状态、许多环境变量、以及通过重定向/管道和(不必要的)使用外部实用程序的到处(不必要的)进程间通信和文件处理。
如何重构shell代码(或在开始时设计它),以便能够使用像bats和mocking-plugin这样的框架来进行“好的”自动化单元测试?

huwehgph

huwehgph1#

单元测试是为了在孤立的代码中发现错误。然而,典型的shell代码主要是与其他可执行文件或操作系统的交互。shell代码中的交互中存在的问题类型是,我是否以正确的顺序调用正确的可执行文件,参数是否以正确的顺序调用,参数值是否格式正确,要测试所有这些,您不应该应用单元测试,而是应用集成测试。
然而,有一些shell代码适合单元测试。例如,在shell中执行计算或字符串操作的代码。我甚至认为调用某些基本函数类工具(如basename)的shell代码适合单元测试(如果你愿意,可以将这些工具解释为“标准库”的一部分)。
如何使shell中适合进行单元测试的代码部分实际上可以通过单元测试进行测试?根据我的经验,最有用的方法之一是将交互与计算分离。也就是说,尝试将计算部分放在单独的shell函数中进行测试,或者将交互主导的部分提取到单独的shell函数中。这可以节省大量的模拟工作。

vwkv1x7d

vwkv1x7d2#

问得好!
恕我直言,shellscripts通常只是调用其他程序来完成任务,比如cpmvtarrsync,...即使对于表达式bash也使用二进制test,如果你使用[ and ](例如if [ -f $file ]; then; fi)。
考虑到这一点,想想bash脚本中真正发生的事情:使用三个参数调用该程序。因此,您可以编写一个unit-tests,它检查bash脚本是否调用了所需的程序并使用了正确的参数,并检查程序的返回值/退出代码。
你肯定不想把你的shell脚本放在单元测试中,这是由另一个程序有效地完成的(例如,检查rsync是否真的从机器A复制文件到机器B)。
只是我的意见

p4tfgftt

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文件完成的,内容是:

mkdir -p test/libs

git submodule add https://github.com/sstephenson/bats test/libs/bats
git submodule add https://github.com/ztombol/bats-support test/libs/bats-support
git submodule add https://github.com/ztombol/bats-assert test/libs/bats-assert

Shell脚本

/src/ is: active_function_string_manipulation.sh`中的shell脚本示例。

##################################################################
# Purpose: Converts a string to lower case
# Arguments:
#   $@ -> String to convert to lower case
##################################################################
function to_lower() 
{
    local str="$@"
    local output
    output=$(tr '[A-Z]' '[a-z]'<<<"${str}")
    echo $output
}
to_lower "$@"

单元测试

单元测试由存储库根目录中的一个名为test.sh的文件运行。它包含以下内容:

# Run this file to run all the tests, once
./test/libs/bats/bin/bats test/*.bats

一个例子是测试:active_function_string_manipulation.sh与:/test/test_active_function_string_manipulation.bats

#!./test/libs/bats/bin/bats

load 'libs/bats-support/load'
load 'libs/bats-assert/load'

@test "running the file in /src/active_function_string_manipulation.sh." {
    input="This Is a TEST"
    run ./src/active_function_string_manipulation.sh "This Is a TEST"
    assert_output "this is a test"
}

Travis CI

Travis CI使用yml文件实现,该文件基本上创建了一个环境并在自动化环境中运行测试。该文件名为:.travis.yml,包含:

language: bash

script:
    - ./test.sh

披露 *

我参与了this repository的构建,它是“for dummies/me”-指令in this article的实现。

注解

我目前对这个系统的扩展能力没有太多的了解,我目前无法估计它是否有潜力成为一个“生产就绪”的系统,或者它是否适合这样的大项目,它仅仅是一个shell代码的自动化单元测试环境。

相关问题