A testing and specification framework for Python 3
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
.idea Split the spec loader so that it only loads specs and does not read t… Sep 5, 2017
nimoy Use the new `@` regex matching syntax in our own tests! Feb 4, 2018
specs Use the new `@` regex matching syntax in our own tests! Feb 4, 2018
.gitignore
.pylintrc Removed invalid `name-warning` from lint Dec 11, 2017
.travis.yml Add Python 3.7 to the build matrix (#10) Aug 6, 2018
CODE_OF_CONDUCT.asciidoc Adding a contribution wiki Dec 7, 2017
CONTRIBUTING.asciidoc Adding a contribution wiki Dec 7, 2017
ISSUE_TEMPLATE.asciidoc Create ISSUE_TEMPLATE.asciidoc Dec 7, 2017
LICENSE
Pipfile Upgrading env to Python 3.7 Jan 14, 2019
Pipfile.lock
README.asciidoc Add a basic contribution section Aug 6, 2018
README.rst Mock assertions (#3) Nov 4, 2017
features_from_spock.md Some "administrative" tasks: Sep 14, 2017
setup.py Add Python 3.7 to the build matrix (#10) Aug 6, 2018

README.asciidoc

Nimoy

A testing and specification framework for Python 3, heavily inspired by the amazing Spock Framework.

PyPI version Build Status

Why?

The Spock Framework has set a new standard as to what testing frameworks should be like - beautiful, expressive, pragmatic and fun.

While unittest, pytest and nose2 are great, there’s still room for improvement.

The aim of this project is to port Spock to Python while maintaining the original vision as much as possible.

Features

  • Based on unittest, so minimal dependencies are required and specifications are recognized by IDEs and report analyzers.

  • Reduction of boilerplate code.

  • Write detailed specifications with clear distinction.

  • Auto discovery of specifications.

  • Write data-driven specifications.

  • Pretty mock behavior assertion.

  • See fancy detailed assertion failure reports.

Examples

Nimoy will pick up on any module ending with _spec.py and will treat any class that ends with the word Spec as a Specification class.

Simple Specification

A specification with a given (alias for setup) and expect block.

Note that conditional statements do not require you to write self.assertX or even assert. Nimoy will still evaluate them.

simple_spec.py
from nimoy.specification import Specification

class MySpec(Specification):

    def my_feature_method(self):
        with given:
            a = 'The quick brown fox'
        with expect:
            a == 'The quick frown box'
$ nimoy

my_feature_method (builtins.MySpec) ... FAIL

======================================================================
FAIL: my_feature_method (builtins.MySpec)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/Users/noam/something/test_spec.py", line 9, in my_feature_method
    a == 'The quick frown box'
  File "/Users/noam/work/private/nimoy/nimoy/specification.py", line 11, in _compare
    Compare().compare(left, right, comparison_type_name)
  File "/Users/noam/work/private/nimoy/nimoy/compare/internal.py", line 21, in compare
    raise AssertionError(error_message) from None
AssertionError:
Expected: 'The quick frown box'
     but: was 'The quick brown fox'
Hint:
- The quick brown fox
?           ^     ^

+ The quick frown box
?           ^     ^


----------------------------------------------------------------------
Ran 1 test in 0.002s

FAILED (failures=1)

Stimulus and Response Specification

A specification with a setup, when and then block. when blocks describe a certain action and then blocks assert the results of that action.

stimulus_and_response_spec.py
from nimoy.specification import Specification

class MySpec(Specification):

    def my_feature_method(self):
        with setup:
            a = 1

        with when:
            a = a + 1

        with then:
            a == 2

Expecting Exceptions

Use the thrown method to make sure that an expected exception has been thrown.

expected_exceptions_spec.py
from nimoy.specification import Specification

class MySpec(Specification):

    def my_feature_method(self):
        with when:
            raise Exception('Whaaaaat')
        with then:
            err = thrown(Exception)
            str(err[1]) == 'Whaaaaat'

Data-driven Specification

Using the powerful where block, we can parametrise our specification and execute it multiple times with different sets of data.

date_driven_spec.py
from nimoy.specification import Specification

class MySpec(Specification):

    def my_feature_method(self):
        with given:
            a = value_of_a
            b = value_of_b

        with expect:
            (a * b) == expected_value

        with where:
            value_of_a | value_of_b | expected_value
            1          | 10         | 10
            2          | 20         | 40

Pretty Mock Assertions

When using unittest Mocks you can write pretty assertions in the then block. Mock assertion expressions are written like a mathematical expression with the format of [NUMBER_OF_INVOCATIONS] * [INVOCATION_TARGET].

[NUMBER_OF_INVOCATIONS] may be a wildcard when filled in with _. Invocation target arguments may also be wildcarded by placing _. For example, class.method(_, 3).

pretty_mock_assertions.py
from unittest import mock
from nimoy.specification import Specification

class MySpec(Specification):

    def my_feature_method(self):
        with setup:
            the_mock = mock.Mock()

        with when:
            the_mock.some_method('abcd', True)

        with then:
            1 * the_mock.some_method('abcd', True)

Syntactic Sugar

Different routine operations have shorthands to make your specifications cleaner and more readable

syntatic_sugar.py
from unittest import mock
from nimoy.specification import Specification

class MySpec(Specification):

    def regex_assertion(self):
        with expect:
            'The quick brown fox' @ '.+brown.+' # This is valid regex matching!

More great features to come!

Contribution

Is most welcome!

Nimoy is branched with the standard git flow conventions so mainline development will be merged to develop; features and PRs to feature branches.

All Code Modifications

Should pass the automated build and be backed up by Nimoy specifications.

New Features

Should include at least one documented example.

License

Apache License 2.0

In memory of Leonard Nimoy 1931-2015