ZUnit is a powerful unit testing framework for ZSH
Go to file
2017-03-09 12:23:54 +00:00
src Bump version 2017-03-08 22:21:04 +00:00
tests Ensure @teardown function is run when a test fails or errors 2017-03-01 20:33:45 +00:00
.gitattributes Add .gitattributes file 2016-09-28 09:28:54 +01:00
.gitignore Separate source files, and add Makefile to compile 2017-02-25 11:25:25 +00:00
.guardian.yml Build and run tests automatically when source files change 2017-02-25 11:25:28 +00:00
.travis.yml Fix incorrect line break in .travis.yml 2017-03-03 21:47:55 +00:00
.zunit.yml Enable time limit in .zunit.yml 2017-02-15 21:27:09 +00:00
.zvmrc First attempt at using zvm to test multiple versions 2017-02-18 16:22:16 +00:00
build.zsh Switch from Makefile to simple ZSH build script 2017-02-25 11:25:27 +00:00
code-of-conduct.md Add code of conduct and contribution guidelines 2017-01-27 17:14:06 +00:00
contributing.md Add code of conduct and contribution guidelines 2017-01-27 17:14:06 +00:00
LICENSE First commit 2016-09-05 22:10:10 +01:00
README.md Mod .travis.yml examples to use zunit from releases, rather than building 2017-03-02 12:55:09 +00:00
zunit.zsh-completion Update usage information and completion to add new --output-html option 2017-02-13 20:17:24 +00:00

ZUnit

Build Status ![Gitter](https://badges.gitter.im/Join Chat.svg)

ZUnit is a powerful unit testing framework for ZSH

Installation

WARNING: Although the majority of ZUnit's functionality works as expected, it is in the early stages of development, and as such bugs are likely to be present. Please continue with caution, and report any issues you may have.

Zulu

zulu install zunit

NOTE: In versions of Zulu prior to 1.2.0, there is an additional step required after install:

cd ~/.zulu/packages/zunit
./build.zsh
zulu link zunit

Manual

git clone https://github.com/molovo/zunit
cd ./zunit
./build.zsh
chmod u+x ./zunit
cp ./zunit /usr/local/bin

ZUnit requires the utilities Color and Revolver to be installed, and in your $PATH. The zulu installation method will install these dependencies for you.

Writing Tests

Test syntax

Tests in ZUnit have a simple syntax, which is inspired by the BATS framework.

#!/usr/bin/env zunit

@test 'My first test' {
	# Test contents here
}

The body of each test can contain any valid ZSH code. The zunit shebang #!/usr/bin/env zunit MUST appear at the top of each test file, or ZUnit will not run it.

Assertions

ZUnit comes with a powerful assertion library to aid you in writing tests. The assert helper function allows you to access each of the available assertions with a readable syntax.

The following assertions are available:

equals

Asserts that two integers are equal to each other.

assert 1 equals 1

not_equal_to

Asserts that two integers are not equal to each other.

assert 1 not_equal_to 0

same_as

Asserts that two strings are equal to each other.

assert 'test' same_as 'test'

different_to

Asserts that two strings are not equal to each other.

assert 'rainbows' different_to 'unicorns'

is_empty

Asserts that a string has a length of zero.

value=''
assert "$value" is_empty

is_not_empty

Asserts that a string has a length of greater than zero.

value='rainbows'
assert $value is_not_empty

matches

Asserts that a string matches a regular expression.

assert 'unicorns' matches '[a-z]{8}'

does_not_match

Asserts that a string does not match a regular expression.

assert 'rainbows' does_not_match '[0-9]+'

in

Asserts that a value is included in the comparison array.

assert 'a' in 'a' 'b' 'c'

not_in

Asserts that a value is not included in the comparison array.

assert 'a' not_in 'x' 'y' 'z'

is_key_in

Asserts that a value is a key in a hash.

typeset -A hash; hash=(
  'a' 1
  'b' 2
  'c' 3
)
assert 'a' is_key_in ${(@kv)hash}

is_not_key_in

Asserts that a value is not a key in a hash.

typeset -A hash; hash=(
  'a' 1
  'b' 2
  'c' 3
)
assert 'x' is_not_key_in ${(@kv)hash}

is_value_in

Asserts that a value is a value in a hash.

typeset -A hash; hash=(
  'a' 1
  'b' 2
  'c' 3
)
assert 1 is_value_in ${(@kv)hash}

is_not_value_in

Asserts that a value is not a value in a hash.

typeset -A hash; hash=(
  'a' 1
  'b' 2
  'c' 3
)
assert 4 is_not_value_in ${(@kv)hash}

exists

Asserts that the given path exists

assert /path/to/file exists

is_file

Asserts that the given path exists and is a file

assert /path/to/file is_file

is_dir

Asserts that the given path exists and is a directory

assert /path/to/dir is_dir

Asserts that the given path exists and is a symbolic link

assert /path/to/link is_link

is_readable

Asserts that the given path exists and is readable

assert /path/to/file is_readable

is_writable

Asserts that the given path exists and is writable

assert /path/to/file is_writable

is_executable

Asserts that the given path exists and is executable

assert /path/to/file is_executable

Loading scripts

Each of your tests is run in isolation, meaning that there is no variable or function leakage between tests. The load helper function will source a script into the test environment for you, allowing you to set up variables and functions etc.

You can load any absolute or relative file path, and for files ending in .zsh including the extension is optional.

# In /mypet.zsh
testing='Tada!'

# In /tests/myscript.zunit
@test 'Test loading scripts' {
	testing=''

	load ../myscript

	assert $testing is_not_empty
	assert $testing same_as 'Tada!'
}

Running commands

You can run commands within your tests using the run helper, allowing you to make assertions on their exit status and output.

@test 'Test command output' {
	# Run the command, including arguments
	run ls ~/my-dir

	# $state contains the exit status
	assert $state equals 0

	# The command's output is stored in $output
	assert $output is_not_empty

	# Each line of the output is also stored in
	# the $lines array, allowing you to run assertions
	# against individual lines of the output
	assert "$lines[3]" equals 'my-third-file'
}

Setup and Teardown

ZUnit provides @setup and @teardown methods, which will be run before and after each test in the file.

@setup {
	SOME_VAR='rainbows'
}

@teardown {
	unset SOME_VAR
}

@test 'Check value of SOME_VAR' {
	assert $SOME_VAR same_as 'rainbows'
}

@test 'Change value of SOME_VAR' {
	SOME_VAR='unicorns'
	assert $SOME_VAR same_as 'unicorns'
}

@test 'Check value of SOME_VAR again' {
	# Check will fail, because the variable was unset in
	# the @teardown method, and then reset to 'rainbows'
	# when @setup was run again.
	assert $SOME_VAR same_as 'unicorns'
}

Configuration

ZUnit is configured using a .zunit.yml file in the base of your project. The default configuration is as follows:

tap: false
directories:
  tests: tests
  output: tests/_output
  support: tests/_support

Bootstrap script

ZUnit will look in the support directory (tests/_support by default) for a file named bootstrap. If found, this is sourced prior to any tests being run. This bootstrap script can be used to install software, set environment variables and source programs required for your tests to run.

Test time limits

ZUnit can enforce a time limit for tests, and will terminate them with an error if they run for longer than this. Just add the time_limit key to your .zunit.yml.

time_limit: 5 # Will terminate tests after they have run for 5 seconds

NOTE: Due to the way child processes are handled in earlier versions of ZSH, the time_limit setting is ignored for ZSH versions below 5.1.0. This is necessary because in versions below 5.1.0, the exit state is never returned from the asynchronous process, which would cause tests to hang indefinitely.

Setting up a new project

To set up ZUnit for a new project, just run zunit init in the project's root directory. This will create the .zunit.yml config file and relevant directories, including a bootstrap script and example test.

Travis CI config

ZUnit can generate a .travis.yml file for you, which contains the build steps needed to install ZUnit's dependencies and then run tests. Just run zunit init --travis when initialising your project.

An example .travis.yml is below:

addons:
  apt:
    packages:
      zsh
install:
  - mkdir .bin
  - curl -L https://github.com/molovo/zunit/releases/download/v0.6.2/zunit > .bin/zunit
  - curl -L https://raw.githubusercontent.com/molovo/revolver/master/revolver > .bin/revolver
  - curl -L https://raw.githubusercontent.com/molovo/color/master/color.zsh > .bin/color
before_script:
  - chmod u+x .bin/{color,revolver,zunit}
  - export PATH="$PWD/.bin:$PATH"
script: zunit

Running Tests

The CLI program zunit is used to run tests.

# Runs all test files in ./tests
zunit

# Runs all test files in ./other_tests
zunit other_tests

# Runs all tests in the file ./tests/a-test-file.zunit
zunit tests/a-test-file.zunit

# Runs a single test named 'The name of the test' in the file
# ./tests/a-test-file.zunit
zunit tests/a-test-file.zunit@'The name of the test'

# Runs all tests, and exists immediately after the first failure
zunit --fail-fast

TAP Compatibility

ZUnit is capable of producing TAP compatible output, either printed to the screen or to an output log, based on options provided.

# Prints TAP compatible output to the screen
zunit --tap

# Prints TAP compatible output to the _output directory
zunit --output-text

HTML Reports

ZUnit is capable of producing a detail HTML report, which you can view in your browser.

# Prints HTML report to the _output directory
zunit --output-html

Risky Tests

By default, risky tests (those that make no assertions) raise a warning in the test output. To supress this behaviour, and allow risky tests to pass without warning, use the --allow-risky option.

zunit --allow-risky

Contributing

All contributions are welcome, and encouraged. Please read our contribution guidelines and code of conduct for more information.

License

Copyright (c) 2016 James Dinsdale hi@molovo.co (molovo.co)

ZUnit is licensed under The MIT License (MIT)

Team