介绍 (Introduction)

In my work I often see well-intended implementations of CI/CD pipelines that might have functional tests but lack unit testing. This impacts the reliability of the functional testing: since the major difference is white-box vs black-box testing, a functional test might succeed even if some components are failing (for instance due to some internal side effect).

在我的工作中,我经常看到CI / CD管道的良好实现,这些实现可能具有功能测试但缺乏单元测试 。 这会影响功能测试的可靠性:由于主要区别在于白盒测试与黑盒测试,因此即使某些组件出现故障(例如由于某些内部副作用),功能测试也可能会成功。

Developers in the Java, Python or Ruby world might be familiar with unit testing using tools like JUnit, PyTest and TestUnit. But what about system administrators that maintain Bash or Powershell scripts? These scripts can contain a lot of functionality and are often used as a dependency in automation.

Java,Python或Ruby世界的开发人员可能熟悉使用JUnitPyTestTestUnit之类的工具进行单元测试。 但是维护BashPowershell脚本的系统管理员呢? 这些脚本可以包含许多功能,并且经常用作自动化中的依赖项。

This challenge inspired me to experiment with some unit testing tools for scripting. So, if you are a System Admin, maintain important Bash and/or Powershell scripts and want to increase reliability through (automated) testing, this might be interesting to you.

这个挑战激发了我尝试一些用于脚本的单元测试工具的经验。 因此,如果您是系统管理员,请维护重要的Bash和/或Powershell脚本,并希望通过(自动)测试来提高可靠性,那么这可能对您很有趣。

使用Bats对Bash脚本进行单元测试 (Unit testing Bash scripts with Bats)

In this blog we will dive into unit testing Bash scripts. I do think that Bash is challenging as a programming language, especially when it comes to variable scope and isolation or how functions are implemented, so we’ll need our scripts to be testable.

在本博客中,我们将深入探讨单元测试Bash脚本。 我确实认为Bash作为一种编程语言具有挑战性,尤其是在涉及可变范围和隔离性或如何实现功能时,因此我们需要脚本是可测试的。

We’re going to use Bats for unit testing Bash scripts. Bats stands for BASH Automated Testing System. It’s a TAP-compliant testing framework for Bash and it provides a simple way to verify that the UNIX programs you write behave as expected.

我们将使用Bats对Bash脚本进行单元测试。 Bats代表BASH自动化测试系统 。 它是Bash的TAP兼容测试框架,它提供了一种简单的方法来验证您编写的UNIX程序是否按预期运行。

可测试的代码有人吗? (Testable code anyone?)

As you might already know, a unit test is a method that instantiates a small portion of an application and verifies its behavior independently from other parts. A good approach for Bash scripts is to define functions to isolate code and make it testable.

您可能已经知道,单元测试是一种实例化应用程序一小部分并独立于其他部分来验证其行为的方法。 Bash脚本的一种好方法是定义函数以隔离代码并使之可测试。

Often there is internal/external interaction between code parts, and we’ll need setup a test double to control the behavior.

通常,代码部分之间存在内部/外部交互,因此我们需要设置一个double测试来控制行为。

让我们开始吧-准备 (Let’s get started — preparation)

For creating and executing our unit tests we’ll use a docker container which will give us a consistent and ephemeral environment. The only thing you’ll need is to have docker engine installed.

为了创建和执行单元测试,我们将使用一个docker容器,该容器将为我们提供一个一致且短暂的环境。 您唯一需要做的就是安装docker引擎 。

The example code for this exercise can be found here. First we need to build our own container image and add additional Bats helpers for testing.

可以在此处找到此练习的示例代码。 首先,我们需要构建自己的容器映像,并添加其他Bats助手进行测试。

This is our Dockerfile:

这是我们的Dockerfile :

FROM bats/bats:latest COPY ./temp_clone_dir /opt/bats-test-helpers WORKDIR /code/

With that we can use this script to clone the bats-helpers code and build our container:

这样,我们可以使用此脚本克隆bats-helpers代码并构建我们的容器:

[ -d "temp_clone_dir" ] && rm -rf "temp_clone_dir"mkdir temp_clone_dir git clone https://github.com/ztombol/bats-support temp_clone_dir/bats-supportgit clone https://github.com/ztombol/bats-assert temp_clone_dir/bats-assertgit clone https://github.com/lox/bats-mock temp_clone_dir/lox-bats-mockdocker build . -t bats-with-helpers:latest

Now let’s write some tests!

现在让我们编写一些测试!

测试1 —断言函数的返回 (Test 1 — assert the return of a function)

Consider this very basic function:

考虑以下非常基本的功能:

# example1.shfunction func1() {  return 1}

We want to make sure that this function always returns 1, and we can easily do this with Bats. We’re going to create a seperate test script and define a positive and a negative test:

我们要确保此函数始终返回1,并且可以使用Bats轻松地做到这一点。 我们将创建一个单独的测试脚本,并定义一个正面和负面的测试:

# test_example1.bats#!/usr/bin/env bats@test "func1 function should return 1" {  source /code/example1.sh  run func1  [ "$status" -eq 1 ]}@test "func1 function should return 2" {  source /code/example1.sh  run func1  [ "$status" -eq 2]}

With ‘@test’ we define a test stanza with a description of our test. The first thing we do is source the function defined in example1.sh. Be aware that it actually executes the commands in the sourced script, as a best practice only define functions in there.

使用“ @test”,我们定义了一个测试节,其中包含对测试的描述。 我们要做的第一件事是获取example1.sh中定义的函数。 请注意,它实际上是在源脚本中执行命令,而最佳实践是仅在其中定义函数。

The run helper executes the function and saves the result and variables $status and $output which can be used for assertion.

运行助手将执行该函数并保存结果和变量$ status$ output ,这些变量可用于断言。

Let’s execute the tests:

让我们执行测试:

The docker container has entrypoint of the bats command, so we simply point to the bats test file as an argument. Bats will then discover available tests (in our case 2) and execute the tests. As expected, the positive test succeeds and the negative test fails. Bats also shows what exactly failed.

docker容器具有bats命令的入口点,因此我们只需将bats测试文件作为参数即可。 蝙蝠将发现可用的测试(在我们的案例2中)并执行测试。 如预期的那样,正面测试成功,而负面测试失败。 蝙蝠还显示出什么完全失败了。

测试2-测试条件和文件突变 (Test 2 — test a condition and a file mutation)

function func2() {  if [ ${ENV_GRASS} = "green" ]  then    touch colors.conf    echo 'grass="green"' > colors.conf  fi}

This function assesses the variable ENV_GRASS and will create a file when the value is ‘green’. Our basic test will assert the condition and the side effect of the file creation:

此函数评估变量ENV_GRASS,并且当值为“绿色”时将创建一个文件。 我们的基本测试将断言文件创建的条件和副作用:

# test_example1.bats#!/usr/bin/env batsload '/opt/bats-test-helpers/bats-support/load.bash'load '/opt/bats-test-helpers/bats-assert/load.bash'@test "func2 function should create config file is grass is green" {  source example1.sh  ENV_GRASS="green"  run func2  assert [ -e 'colors.conf' ]}@test "func2 function should not create config file if grass is not green" {  source example1.sh  ENV_GRASS="red"  run func2  assert [ ! -e 'colors.conf' ]}

For this test we’ll use the bats-helper bats-assert which has a lot of testing functionality. Again we’re sourcing our function, declaring the ENV_GRASS variable, executing the function and assert that the file is created/not created.

对于此测试,我们将使用具有很多测试功能的bats-helper bats-assert 。 再次,我们提供函数,声明ENV_GRASS变量,执行函数并断言该文件已创建/未创建。

测试3-测试Terraform包装器脚本 (Test 3 — test a terraform wrapper script)

When I use Terraform I’d like to use a wrapper script that sets things up. For instance, this function makes sure the .terraform directory does not exist before we do a terraform init:

当我使用Terraform时,我想使用一个包装器脚本来进行设置。 例如,此函数确保在执行terraform初始化之前.terraform目录不存在

init_tf() {  if [ -d ".terraform" ]; then    echo "unclean working dir, .terraform dir still exists. removing .terraform"    rm -rf .terraform  fi  terraform init -input=false}

This gives us ample testing angles:

这给了我们充足的测试角度:

  • We do not want terraform init to actually be called, so we’ll need to stub the terraform command which we can do with the bats-helper bats-mock

    我们不希望真正调用terraform init,因此我们需要对terraform命令进行存根处理 ,这可以通过bats-helper bats-mock来完成。

  • The init_tf function should remove the directory .terraform if exists如果存在,init_tf函数应删除目录.terraform
  • The init_tf function should print message if the directory .terraform exists如果目录.terraform存在,则init_tf函数应打印消息

Our test code looks like this:

我们的测试代码如下:

# test_example_tf_plan.bats#!/usr/bin/env batsload '/opt/bats-test-helpers/bats-support/load.bash'load '/opt/bats-test-helpers/bats-assert/load.bash'load '/opt/bats-test-helpers/lox-bats-mock/stub.bash'setup() {  stub terraform \  "'init -input=false' : echo 'I am stubbed for terraform init!'"  if [ -d .terraform ] ; then rm -rf .terraform ; fi}@test "init_tf function should remove dir .terraform if exists" {  source example_tf_plan.sh  mkdir .terraform  run init_tf  assert [ ! -d '.terraform' ]}@test "init_tf function should print message if dir. .terraform exists" {  source example_tf_plan.sh  mkdir .terraform  run init_tf  assert_output "unclean working dir, .terraform dir still exists. removing .terraform"}

This time we’re loading the bat-mock helper and we have another section ‘setup’. In setup you can set things up that are needed for our tests. Firstly we are stubbing the terraform command with specific arguments, so that it doesn’t hit the actual terraform binary. Secondly we need the .terraform directory not to exist for our tests. Now that we have a setup we can define the tests.

这次我们正在加载蝙蝠模拟助手,我们还有另一部分“设置” 。 在设置中,您可以设置测试所需的内容。 首先,我们使用特定的参数对terraform命令进行存根处理,以便它不会命中实际的terraform二进制文件。 其次,我们需要测试不存在.terraform目录。 现在我们有了设置,可以定义测试了。

The first test asserts that the .terraform directory is deleted if it exists. We’re sourcing the function, deliberately creating the .terraform directory, run the function and asserting the directory.

第一个测试断言.terraform目录已删除。 我们正在寻找该函数,有意创建.terraform目录,运行该函数并声明该目录。

The second test is doing the same, but then asserting the message output.

第二个测试也在做相同的事情,但是随后声明了消息输出。

结论 (Conclusion)

As you can see, it’s quite easy to increase test coverage for your Bash scripts which gives you more confident in the system. Whenever someone breaks a script, the unit tests in the pipeline should fail.

如您所见,增加Bash脚本的测试覆盖范围很容易,这使您对系统更有信心。 每当有人破坏脚本时,管道中的单元测试都将失败。

Next up is Powershell, stay tuned!

接下来是Powershell,敬请期待!

翻译自: https://medium.com/@marck.oemar/unusual-unit-testing-part-1-bash-scripts-with-bats-55ac78e61491


http://www.taodudu.cc/news/show-4629361.html

相关文章:

  • 使用更便捷的时间序列预测模型 2022-6-2
  • hadoop3源码编译
  • 对小部分bats的守护进程
  • bats指哪几家公司_用BATS测试Bash
  • NCE4 L7 Bats
  • 【云原生】Prometheus+Grafana on K8s 环境部署
  • 神经网络架构搜索——二值可微分搜索(BATS)
  • 鼻子的保健与健康
  • Vue3.x 报 Uncaught TypeError:Object(...) is not a function( Vue3对象不是函数解决思路)
  • 【解决】控制台报错Uncaught TypeError: Object(...) is not a function at eval (vue-router.esm-bundler.js
  • React的React.FC与React.Component
  • 计算机组成原理fc和fz,合肥工业大学计算机组成原理实验报告(DOC)
  • opencv mat 类型转换 CV_32FC1--CV_8U
  • 安装openssl和openssl-devel
  • React的React.FC与React.Component的初步认识
  • 无法登陆github的解决方法
  • NetApp FAS FC相关基础配置案例
  • 最全FC交换机基础知识详解
  • 初学FC网络
  • 《软件功能测试自动化实战教程》—第6章6.5节使用环境变量的参数化
  • 《软件功能测试自动化实战教程》—第6章6.4节Action测试输入的参数化
  • 《软件功能测试自动化实战教程》—第6章6.7节文件数据源的数据驱测试
  • 《软件功能测试自动化实战教程》—第6章6.3节参数化测试
  • 201621123031 《Java程序设计》第7周学习总结
  • 201421123042 《Java程序设计》第4周学习总结
  • 201421123042 《Java程序设计》第5周学习总结
  • 201621123031 《Java程序设计》第4周学习总结
  • 201621123031 《Java程序设计》第5周学习总结
  • 201621123031 《Java程序设计》第11周学习总结
  • 201421123042 《Java程序设计》第11周学习总结

不寻常的单元测试,第1部分:带蝙蝠的bash脚本相关推荐

  1. Jmeter Web 性能测试入门 (四):一个小实例带你学会 Jmeter 脚本编写

    测试场景: 模拟并发100个user,在TesterHome 站内搜索VV00CC 添加线程组 添加HTTP信息头管理器 添加HTTP Sampler 填写HTTP Sampler中的信息 添加监听器 ...

  2. SQL Server自带备份整个数据库脚本工具

    首先在sqlserver的安装路径下,如:D:\Program Files\Microsoft SQL Server\MSSQL\,找到文件名是scptxfr.exe的文件,利用命令行工具:具体用法如 ...

  3. 丢失__EVENTTARGET _dopost Asp.net自带隐藏域和脚本的现象

    最近有一个程序突然出错, 发现以前自己在程序中写了一个Javascript函数来调用Asp.net自带的__dopost函数  function deleteApplication(eventTarg ...

  4. 抖音电商主播运营带货话术脚本策划方案流程计划表格

    直播带货方案大全(点此网盘下载) 这节课由我来给大家教授 CD 2018 基础操作命令.那么我们现在所看到的就是一个 2018 的界面.那么在这个界面我们没有像以前的 2014 的一样,2007的一样 ...

  5. linux shell 数组元素带空格,在bash中解析带有空格的JSON数组

    我试图解析下面的json数组并从中获取值.但它不能将空间作为值.我确实在 stackoverflow 但似乎没用. JSON格式 { "apps": [ { "name& ...

  6. c代码中 执行sh文件 带参数_创建含有$1参数的Bash脚本以及运行脚本的三种方法...

    一.先创建一个简易脚本 要求: 1.创建一个名为demo.sh的文件,如果该脚本后跟上文件名某某某,就会产生一个名为某某的文件夹 2.某某某文件内要有一个index.html及文件夹css和文件夹js ...

  7. python单击url下载网页文件_使用不带url的python脚本从网页下载文件,调用onClick函数 - javascript...

    有一个网页带有链接"单击下载",单击该链接可以下载文件. 我可以通过转到网页并单击此链接来手动下载此文件,但是我需要通过python脚本下载此文件. 如果我看到源代码,则可以看到锚 ...

  8. SQL Server 2008 R2如何生成带数据的数据库脚本

    1.对想要复制的数据库右键,"任务","生成脚本" 2.下面需要注意的是,默认情况下,只会生成仅架构的脚本,也就是说仅仅有表结构,而没有数据的空壳.所以需要额外 ...

  9. Erwin 生成 mysql 带注释(comment )的脚本

    Erwin设计数据库非常方便,有逻辑视图和物理视图,可以很方便的生成数据库文档和SQL 脚本.在使用过程中唯一不爽的地方是脚本不能生成comment. 在百度无数次无法解决下,又翻墙谷歌,在一个日本网 ...

最新文章

  1. Docker的容器运行时组件Containerd
  2. (一)python3 只需3小时带你轻松入门—— 编程尝试
  3. 定义变量和常量的规范 c语言,C语言编程规范教材及练习(标识符命名与定义 变量 宏、常量 表的达式).pptx...
  4. java key value 数据类型_JAVA面试锦囊(一)
  5. 基于改进麻雀算法优化变分模态分解(IAMSSA—VMD)的信号分解方法
  6. DELMIA人机工程 ---- 二次开发 第一篇:开发指南
  7. 让Mac文本编辑器成为HTML编辑器
  8. html表单界面设计,ui界面表单设计的三个方面
  9. Ubuntu18.04安装搜狗输入法使用时不能输入中文
  10. 解除WORD文档保护
  11. Java 获取月初时间
  12. CKPT,SMON,PMON,RECO,Dnnn
  13. chrome浏览器抓包工具介绍(2022,12,27)
  14. 前端测试 -- sinon.js
  15. C# 静态和非静态的区别
  16. matlab 矩阵的n次,用matlab的for循环产生N个矩阵,怎么取第N次的矩阵?
  17. 2,未来十年,资产增加
  18. 传智播客成都Java培训中心
  19. 我们为什么需要光纤配线架
  20. 小程序页面传值、页面与组件通信方式总结

热门文章

  1. Unity导入package简单操作流程
  2. HTTP content-type
  3. 小程序canvas绘图保存至相册
  4. Ping Pong Buffer 双缓冲 C++代码学习
  5. IoT设备配网方式总结
  6. 1. 工业大数据的内涵
  7. 人工智能等新技术将会给人们的生产、生活方式带来革命性的变化
  8. linux双屏原理,Linux下双屏显示设置
  9. .NET的资源并不限于.resx文件(二)
  10. Android常用三方框架