
Testing Bash Applications
Recently, I was faced with the task of testing an application written in Bash. Initially, I decided to use unit tests in Python, however, I did not want to add extra technology to the project. And I had to choose a test framework whose mother tongue is the long-suffering Bash.
When I turned to Google asking: what there is already a choice, the answer was not so many options. Here I will consider some of them.
What criteria will I pay attention to?
One of the first options that I noticed was a small framework
Of the advantages, you can further highlight:
There are several serious disadvantages:
Conclusion: a good tool that I would recommend using if you need to write a couple of simple tests for a script. For more serious tasks - not suitable.
Things
This framework has a number of unique features in its class:
But there are a number of significant drawbacks that pushed me as a result:
Conclusion: a serious tool that can be flexibly configured and turned into an indispensable part of the project, but the lack of a clear system for managing the project itself scares
I was initially interested in this framework, because it was written by the author
There are no examples of the conclusion to look - you need to put and check, bad. Here are the advantages:
And there were enough minuses:
Conclusion: such an average thing is absolutely average, one cannot say that it is bad. But you can’t call her good either. The functionality is similar to
I have to say right away, I chose this framework. Liked a lot. First of all - excellent documentation: examples of use, semantic versioning, separately pleased with the list of projects that use
The output of information about tests using the flag (
In
Objectively, there are
Conclusion: a quality tool, with virtually no weaknesses. I advise to use.
If you are interested to see what happened in the end, here is a link to the tests for my free-time project
Overview of existing solutions
When I turned to Google asking: what there is already a choice, the answer was not so many options. Here I will consider some of them.
What criteria will I pay attention to?
- Dependencies: if we take the test framework on Bash, then I would like it to not pull for itself: Python, Lua, and a couple more system packages (and there are some).
- The complexity of the installation: since one of the tasks was the deployment of continuous-development and continuous-integration in Travis , it was important for me that the installation could be done in a sane time and number of steps. Ideal options: package managers, acceptable:
git clone
,wget
. - Documentation and support: the application should work on different unix distributions, respectively, and the tests should work everywhere, taking into account the number of different platforms, shells, their combinations and the speed of updating them, I would not want to stay without the community and experience of other users.
- The presence of fixtures in any form and / or (at least!)
setup()
Andteardown()
functions. - Sane syntax for writing new tests. In the world of Bash, a very important requirement.
- My usual conclusion about the results of the tests: how much has passed, what and where has fallen, in which line (preferably).
assert.sh
One of the first options that I noticed was a small framework
assert.sh
. Fairly good solution: easy to install, easy to use. In order to write the first tests you need to create a file tests.sh
and write just something into it (example from the documentation):Expand
Then you can run the tests and see the results:
. assert.sh
# `echo test` is expected to write "test" on stdout
assert "echo test" "test"
# `seq 3` is expected to print "1", "2" and "3" on different lines
assert "seq 3" "1\n2\n3"
# exit code of `true` is expected to be 0
assert_raises "true"
# exit code of `false` is expected to be 1
assert_raises "false" 1
# end of test suite
assert_end examples
Then you can run the tests and see the results:
$ ./tests.sh
all 4 examples tests passed in 0.014s.
Of the advantages, you can further highlight:
- Ease of syntax and use.
- Good documentation, examples of use.
- The ability to do conditional or unconditional skip tests.
- Opportunity fail-fast or run-all.
- It is possible to make the error output detailed (if you use the flag
-v
), initially it does not say which tests fall.
There are several serious disadvantages:
- At the time of writing the article on github, the red "build failing" icon was on, it looks scary.
- The framework positions itself as light, it lacks methods for me
setup()
andteardown()
so that it is possible to prepare the necessary data for each test and delete it at its completion. - There is no way to run all test files from a specific folder.
Conclusion: a good tool that I would recommend using if you need to write a couple of simple tests for a script. For more serious tasks - not suitable.
shunit2
Things
shunit2
are worse with the installation . I could not find an adequate repository: there is a certain project on Google.Code, there are several projects on github of various neglect (3 years and 5 years), there are even several svn repositories. Accordingly, it is unrealistic to understand which release is the latest and where to download it from. But then the little things. What do the tests themselves look like? Here is a slightly simplified example from the documentation :Expand
Performance:
testAdding()
{
result=`expr 1 + 2`
assertEquals \
"the result of '${result}' was wrong" \
3 "${result}"
}
Performance:
$ /bin/bash math_test.sh
testAdding
Ran 1 test.
OK
This framework has a number of unique features in its class:
- The ability to create suites within the code, such a function can be useful, there are tests for specific platforms or shells. Then you can use your namespaces, like
zsh_
,debian_
etc. - There are functions
setUp
andtearDown
that are performed for each test, and anotheroneTimeSetUp
, andoneTimeTearDown
that are performed at the beginning and end of the test. - A wide selection of different ones
assert
, it is possible to display line numbers where the test falls using the design${_ASSERT_EQUALS_}
, but only in shells where line numbering is supported. From the documentation:bash
(> = 3.0)ksh
,pdksh
andzsh
. - It is possible to skip tests.
But there are a number of significant drawbacks that pushed me as a result:
- There is no activity in the project, all the latest errors in Google.Code since 2012 hang without a solution, there have not been any commits to the repository for three years now. In general, trouble.
- It is not clear what and how to put, the last release was in 2011. Associated with the last paragraph.
- The number of functions is even slightly redundant, so there are two ways to check equality:
assertEquals
andassertSame
. A trifle, but surprising. - There is no way to run all files from a folder.
Conclusion: a serious tool that can be flexibly configured and turned into an indispensable part of the project, but the lack of a clear system for managing the project itself scares
shunit2
. I decided to search further.roundup
I was initially interested in this framework, because it was written by the author
Sinatra
for Ruby
. I also liked the test syntax, which resembles the familiar and familiar Mocha
. By default, all functions that start with the it_
inside of the file are launched . Interestingly, all tests are run inside their own sandbox, which helps prevent unnecessary errors. And here are the tests themselves, an example from the documentation:Expand
describe "roundup(5)"
before() {
foo="bar"
}
after() {
rm -f foo.txt
}
it_runs_before() {
test "$foo" "=" "bar"
}
There are no examples of the conclusion to look - you need to put and check, bad. Here are the advantages:
- Each test runs inside its sandbox, which is very convenient.
- Easy to use.
- Installation through
git clone
and./configure && make
, can be installed in a local directory with the addition of$PATH
.
And there were enough minuses:
- There is no way to do
source
some common functions for all tests, but in fairness it’s worth saying that with the help of a hack - you can. - There is no way to run all test files from a folder.
- Documentation is replete
TODO
, but work has not been carried out for a couple of years. - You can not miss the test.
Conclusion: such an average thing is absolutely average, one cannot say that it is bad. But you can’t call her good either. The functionality is similar to
assert.sh
, only a little more. Where to use? If there is enough functionality assert.sh
, but you need a function before()
or after()
.bats
I have to say right away, I chose this framework. Liked a lot. First of all - excellent documentation: examples of use, semantic versioning, separately pleased with the list of projects that use
bats
. bats
uses the following approach: a test is considered passed if all the commands inside it return a code 0
(how set -e
). That is, each line is a truth check. Here's what the tests written in bats
:Expand
And the conclusion:
#!/usr/bin/env bats
@test "addition using bc" {
result="$(echo 2+2 | bc)"
[ "$result" -eq 4 ]
}
@test "addition using dc" {
result="$(echo 2 2+p | dc)"
[ "$result" -eq 4 ]
}
And the conclusion:
$ bats addition.bats
✓ addition using bc
✓ addition using dc
2 tests, 0 failures
The output of information about tests using the flag (
--tap
) can be represented in the form of text compatible with Test Anything Protocol
, for which there are plugins for more programs: Jenkins, Redmine and others. In
bats
addition to the special syntax for writing a test, there are many interesting things:- The command
run
allows you to run the command and then test its output code and text output: for which there are special variables:$status
and$output
- The command
load
allows you to load a common code base for use. - The command
skip
allows you to skip the test if necessary. - Functions
setup()
andteardown()
allow you to customize the environment and clean up for yourself. - There are a number of special environment variables .
- It is possible to run all test files inside a folder.
- Active community.
Objectively, there are
bats
a lot of pluses , and I have already listed them, but minus I could notice only one:bats
departs from the validbash
. Tests must be written in files with permission.bats
, use another shebang.
Conclusion: a quality tool, with virtually no weaknesses. I advise to use.
PS
If you are interested to see what happened in the end, here is a link to the tests for my free-time project
git-secret
.