Bats Concepts: Difference between revisions

From NovaOrdis Knowledge Base
Jump to navigation Jump to search
 
(17 intermediate revisions by the same user not shown)
Line 4: Line 4:
=Overview=
=Overview=


Shell scripts can be tested easier if the functionality is broken into many small, reusable and independently testable functions.
Shell scripts can be tested easier if the functionality is broken into many small, reusable and independently testable functions. A library that packages such functions can be tested by sourcing the library into the BATS test and then running the functions no different than how their usual calling layer would invoke them.


A library of such functions can be tested by sourcing the library into the BATS test and run the functions as their usual calling layer would invoke them.
==bats-core vs bats==
 
Apparently bats-core supersedes bats, and it should be used instead. One difference is that bats error reports are included as comments, not part of tap output, and are not therefore propagated to the Xunit version of tap-xunit. In other words, bats-core includes builtin xunit output.


=Test=
=Test=
Line 16: Line 18:


     run my-command status
     run my-command status
     [[ ${status} -eq 0 ]]
     [[ ${status} -eq 0 ]] || echo "${output}"
     [[ ${output} =~ We[[:space:]]are[[:space:]]good ]]
     [[ ${output} =~ We[[:space:]]are[[:space:]]good ]] || echo "${output}"
}
}
</syntaxhighlight>
</syntaxhighlight>


The label that follows @test may include spaces.
The quoted-enclosed label that follows @test may include spaces.


The functionality to be tested, most likely a function, must be executed with "run", as shown above. If executed that way,  [[#.24.7Bstatus.7D|${status}]] and  [[#.24.7Boutput.7D|${output}]] are updated accordingly.
The functionality to be tested, most likely a function, must be executed with "run", as shown above. If executed that way,  [[#.24.7Bstatus.7D|${status}]] and  [[#.24.7Boutput.7D|${output}]] are updated accordingly.
Line 27: Line 29:
Tests are executed in the order they're specified in the file.
Tests are executed in the order they're specified in the file.


In all tests, $0 is /usr/local/Cellar/bats/0.4.0/libexec/bats-exec-test (or however BATS was installed on the system)
In all tests, $0 is <code>/usr/local/Cellar/bats/0.4.0/libexec/bats-exec-test</code> (or wherever BATS was installed on the system).


==Displaying from Test==
==Displaying from Test==
Line 42: Line 44:
==Test Environment==
==Test Environment==


BATS uses [[exec]] to run each @test block as a separate subprocess. This makes it possible to export environment variables and even functions in one @test without affecting the other @tests or polluting the current shell session.
BATS uses <code>[[exec]]</code> to run each <code>@test</code> block as a separate subprocess. This makes it possible to export environment variables and even functions in one <code>@test</code> without affecting the other <code>@test</code>s or polluting the current shell session.


==Run a Command and Check the Status and Output==
==Run a Command and Check the Status and Output==
Line 56: Line 58:
===${status}===
===${status}===
<syntaxhighlight lang='bash'>
<syntaxhighlight lang='bash'>
[[ ${status} == 0 ]] || { echo ${output}; exit 1; }
[[ ${status} -eq 0 ]] || { echo ${output}; exit 1; }
[[ ${status} -eq 0 ]] || { echo ${output}; exit 1; }
</syntaxhighlight>
</syntaxhighlight>
Line 68: Line 71:
run ${some_command}
run ${some_command}
[[ ${output} =~ .*Stack[[:space:]]test[[:space:]]is[[:space:]]stable[[:space:]]and[[:space:]]running* ]]
[[ ${output} =~ .*Stack[[:space:]]test[[:space:]]is[[:space:]]stable[[:space:]]and[[:space:]]running* ]]
</syntaxhighlight>
<syntaxhighlight lang='bash'>
[[ -z ${output} ]] || { echo ${output}; exit 1; }
</syntaxhighlight>
</syntaxhighlight>


Line 73: Line 80:
For multi-line output, individual lines can be accessed with:
For multi-line output, individual lines can be accessed with:


<font size=-1>
  ${lines[0]}
  ${lines[0]}
  ${lines[1]}
  ${lines[1]}
  ...
  ...
</font>


As in [[#.24.7Boutput.7D|${output}]]'s case, sdtout and stderr are coalesced.
As in [[#.24.7Boutput.7D|${output}]]'s case, sdtout and stderr are coalesced.
To test the number of lines:
<syntaxhighlight lang='bash'>
[[ ${#lines[@]} == 3 ]]
</syntaxhighlight>


=Setup/Teardown=
=Setup/Teardown=


If the BATS script includes setup() and teardown() functions, they are automatically executed by BATS before and after each test block runs.
If the BATS script includes <code>setup()</code> and <code>teardown()</code> functions, they are automatically executed by BATS before and after each test block runs.


<syntaxhighlight lang='bash'>
<syntaxhighlight lang='bash'>
Line 95: Line 110:
=Libraries being Tested and Helpers=
=Libraries being Tested and Helpers=


Like any shell script or library, BATS test scripts can include helper libraries to share common code across tests. Libraries can be placed in the same test directory as the BATS scripts or in the test/libs directory, and loaded with the "load" function. The "load" function takes a path to a Bash file relative to the script being tested and sources that file. Files must end with the prefix .bash, but the path to the file passed to the load function can't include the prefix.
Like any shell script or library, BATS test scripts can include helper libraries to share common code across tests. Libraries can be placed in the same test directory as the BATS scripts or in the <code>test/libs</code> directory, and loaded with the <code>load</code> function. The <code>load</code> function takes a path to a bash file relative to the script being tested and sources that file. Files must end with the <code>.bash</code> prefix, but the path to the file passed to the <code>load</code> function must not include the prefix.


Also see: {{Internal|Bats_Operations#Loading_a_Library_to_be_Tested_into_a_.bats_Test|Loading a Library to be Tested into a .bats Test}}
Also see: {{Internal|Bats_Operations#Loading_a_Library_to_be_Tested_into_a_.bats_Test|Loading a Library to be Tested into a .bats Test}}


=Environment Variables=
=Environment Variables=
{{External|https://bats-core.readthedocs.io/en/latest/writing-tests.html#special-variables}}
{{External|https://github.com/sstephenson/bats#special-variables}}
{{External|https://github.com/sstephenson/bats#special-variables}}


==BATS_TEST_DIRNAME==
==BATS_TEST_DIRNAME==


The directory in which the Bats test file is located.
The directory in which the Bats test file is located.
==BATS_TMPDIR==
The location to a directory that may be used to store temporary files.
==BATS_TEST_NAMES==
Array.
==BATS_TEST_NUMBER==
The (1-based) index of the current test case in the test file.

Latest revision as of 23:26, 25 July 2023

Internal

Overview

Shell scripts can be tested easier if the functionality is broken into many small, reusable and independently testable functions. A library that packages such functions can be tested by sourcing the library into the BATS test and then running the functions no different than how their usual calling layer would invoke them.

bats-core vs bats

Apparently bats-core supersedes bats, and it should be used instead. One difference is that bats error reports are included as comments, not part of tap output, and are not therefore propagated to the Xunit version of tap-xunit. In other words, bats-core includes builtin xunit output.

Test

An individual test is placed into a @test-annotated code block.

@test "something" {

    run my-command status
    [[ ${status} -eq 0 ]] || echo "${output}"
    [[ ${output} =~ We[[:space:]]are[[:space:]]good ]] || echo "${output}"
}

The quoted-enclosed label that follows @test may include spaces.

The functionality to be tested, most likely a function, must be executed with "run", as shown above. If executed that way, ${status} and ${output} are updated accordingly.

Tests are executed in the order they're specified in the file.

In all tests, $0 is /usr/local/Cellar/bats/0.4.0/libexec/bats-exec-test (or wherever BATS was installed on the system).

Displaying from Test

@test "something" {

    run ...

    echo ${status}
}

Test Environment

BATS uses exec to run each @test block as a separate subprocess. This makes it possible to export environment variables and even functions in one @test without affecting the other @tests or polluting the current shell session.

Run a Command and Check the Status and Output

some_command=....
[...]
run ${some_command}
[[ ${status} -eq 0 ]]
[[ ${output} =~ .*Stack[[:space:]]test[[:space:]]is[[:space:]]stable[[:space:]]and[[:space:]]running* ]]

${status}

[[ ${status} == 0 ]] || { echo ${output}; exit 1; }
[[ ${status} -eq 0 ]] || { echo ${output}; exit 1; }

${output}

$(output) coalesce lines:

some_command=....
[...]
run ${some_command}
[[ ${output} =~ .*Stack[[:space:]]test[[:space:]]is[[:space:]]stable[[:space:]]and[[:space:]]running* ]]
[[ -z ${output} ]] || { echo ${output}; exit 1; }

${lines}

For multi-line output, individual lines can be accessed with:

${lines[0]}
${lines[1]}
...

As in ${output}'s case, sdtout and stderr are coalesced.

To test the number of lines:

[[ ${#lines[@]} == 3 ]]

Setup/Teardown

If the BATS script includes setup() and teardown() functions, they are automatically executed by BATS before and after each test block runs.

function setup() {
 ...
}

function teardown() {
 ...
}

Libraries being Tested and Helpers

Like any shell script or library, BATS test scripts can include helper libraries to share common code across tests. Libraries can be placed in the same test directory as the BATS scripts or in the test/libs directory, and loaded with the load function. The load function takes a path to a bash file relative to the script being tested and sources that file. Files must end with the .bash prefix, but the path to the file passed to the load function must not include the prefix.

Also see:

Loading a Library to be Tested into a .bats Test

Environment Variables

https://bats-core.readthedocs.io/en/latest/writing-tests.html#special-variables
https://github.com/sstephenson/bats#special-variables


BATS_TEST_DIRNAME

The directory in which the Bats test file is located.

BATS_TMPDIR

The location to a directory that may be used to store temporary files.

BATS_TEST_NAMES

Array.

BATS_TEST_NUMBER

The (1-based) index of the current test case in the test file.