17.12
This commit is contained in:
@@ -0,0 +1,322 @@
|
||||
PyHamcrest
|
||||
==========
|
||||
|
||||
| |docs| |travis| |coveralls| |landscape| |scrutinizer| |codeclimate|
|
||||
| |version| |downloads| |wheel| |supported-versions| |supported-implementations|
|
||||
|
||||
.. |docs| image:: https://readthedocs.org/projects/pyhamcrest/badge/?style=flat
|
||||
:target: https://pyhamcrest.readthedocs.org/
|
||||
:alt: Documentation Status
|
||||
|
||||
.. |travis| image:: http://img.shields.io/travis/hamcrest/PyHamcrest/master.png?style=flat
|
||||
:alt: Travis-CI Build Status
|
||||
:target: https://travis-ci.org/hamcrest/PyHamcrest
|
||||
|
||||
.. |appveyor| image:: https://ci.appveyor.com/api/projects/status/github/hamcrest/PyHamcrest?branch=master
|
||||
:alt: AppVeyor Build Status
|
||||
:target: https://ci.appveyor.com/project/hamcrest/PyHamcrest
|
||||
|
||||
.. |coveralls| image:: http://img.shields.io/coveralls/hamcrest/PyHamcrest/master.png?style=flat
|
||||
:alt: Coverage Status
|
||||
:target: https://coveralls.io/r/hamcrest/PyHamcrest
|
||||
|
||||
.. |landscape| image:: https://landscape.io/github/hamcrest/PyHamcrest/master/landscape.svg?style=flat
|
||||
:target: https://landscape.io/github/hamcrest/PyHamcrest/master
|
||||
:alt: Code Quality Status
|
||||
|
||||
.. |codeclimate| image:: https://codeclimate.com/github/hamcrest/PyHamcrest/badges/gpa.svg
|
||||
:target: https://codeclimate.com/github/hamcrest/PyHamcrest
|
||||
:alt: Code Climate
|
||||
|
||||
.. |version| image:: http://img.shields.io/pypi/v/PyHamcrest.png?style=flat
|
||||
:alt: PyPI Package latest release
|
||||
:target: https://pypi.python.org/pypi/PyHamcrest
|
||||
|
||||
.. |downloads| image:: http://img.shields.io/pypi/dm/PyHamcrest.png?style=flat
|
||||
:alt: PyPI Package monthly downloads
|
||||
:target: https://pypi.python.org/pypi/PyHamcrest
|
||||
|
||||
.. |wheel| image:: https://pypip.in/wheel/PyHamcrest/badge.png?style=flat
|
||||
:alt: PyPI Wheel
|
||||
:target: https://pypi.python.org/pypi/PyHamcrest
|
||||
|
||||
.. |supported-versions| image:: https://pypip.in/py_versions/PyHamcrest/badge.png?style=flat
|
||||
:alt: Supported versions
|
||||
:target: https://pypi.python.org/pypi/PyHamcrest
|
||||
|
||||
.. |supported-implementations| image:: https://pypip.in/implementation/PyHamcrest/badge.png?style=flat
|
||||
:alt: Supported imlementations
|
||||
:target: https://pypi.python.org/pypi/PyHamcrest
|
||||
|
||||
.. |scrutinizer| image:: https://img.shields.io/scrutinizer/g/hamcrest/PyHamcrest/master.png?style=flat
|
||||
:alt: Scrtinizer Status
|
||||
:target: https://scrutinizer-ci.com/g/hamcrest/PyHamcrest/
|
||||
|
||||
|
||||
Introduction
|
||||
============
|
||||
|
||||
PyHamcrest is a framework for writing matcher objects, allowing you to
|
||||
declaratively define "match" rules. There are a number of situations where
|
||||
matchers are invaluable, such as UI validation, or data filtering, but it is in
|
||||
the area of writing flexible tests that matchers are most commonly used. This
|
||||
tutorial shows you how to use PyHamcrest for unit testing.
|
||||
|
||||
When writing tests it is sometimes difficult to get the balance right between
|
||||
overspecifying the test (and making it brittle to changes), and not specifying
|
||||
enough (making the test less valuable since it continues to pass even when the
|
||||
thing being tested is broken). Having a tool that allows you to pick out
|
||||
precisely the aspect under test and describe the values it should have, to a
|
||||
controlled level of precision, helps greatly in writing tests that are "just
|
||||
right." Such tests fail when the behavior of the aspect under test deviates
|
||||
from the expected behavior, yet continue to pass when minor, unrelated changes
|
||||
to the behaviour are made.
|
||||
|
||||
Installation
|
||||
============
|
||||
|
||||
Hamcrest can be installed using the usual Python packaging tools. It depends on
|
||||
distribute, but as long as you have a network connection when you install, the
|
||||
installation process will take care of that for you.
|
||||
|
||||
My first PyHamcrest test
|
||||
========================
|
||||
|
||||
We'll start by writing a very simple PyUnit test, but instead of using PyUnit's
|
||||
``assertEqual`` method, we'll use PyHamcrest's ``assert_that`` construct and
|
||||
the standard set of matchers:
|
||||
|
||||
.. code:: python
|
||||
|
||||
from hamcrest import *
|
||||
import unittest
|
||||
|
||||
class BiscuitTest(unittest.TestCase):
|
||||
def testEquals(self):
|
||||
theBiscuit = Biscuit('Ginger')
|
||||
myBiscuit = Biscuit('Ginger')
|
||||
assert_that(theBiscuit, equal_to(myBiscuit))
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
||||
The ``assert_that`` function is a stylized sentence for making a test
|
||||
assertion. In this example, the subject of the assertion is the object
|
||||
``theBiscuit``, which is the first method parameter. The second method
|
||||
parameter is a matcher for ``Biscuit`` objects, here a matcher that checks one
|
||||
object is equal to another using the Python ``==`` operator. The test passes
|
||||
since the ``Biscuit`` class defines an ``__eq__`` method.
|
||||
|
||||
If you have more than one assertion in your test you can include an identifier
|
||||
for the tested value in the assertion:
|
||||
|
||||
.. code:: python
|
||||
|
||||
assert_that(theBiscuit.getChocolateChipCount(), equal_to(10), 'chocolate chips')
|
||||
assert_that(theBiscuit.getHazelnutCount(), equal_to(3), 'hazelnuts')
|
||||
|
||||
As a convenience, assert_that can also be used to verify a boolean condition:
|
||||
|
||||
.. code:: python
|
||||
|
||||
assert_that(theBiscuit.isCooked(), 'cooked')
|
||||
|
||||
This is equivalent to the ``assert_`` method of unittest.TestCase, but because
|
||||
it's a standalone function, it offers greater flexibility in test writing.
|
||||
|
||||
|
||||
Predefined matchers
|
||||
===================
|
||||
|
||||
PyHamcrest comes with a library of useful matchers:
|
||||
|
||||
* Object
|
||||
|
||||
* ``equal_to`` - match equal object
|
||||
* ``has_length`` - match ``len()``
|
||||
* ``has_property`` - match value of property with given name
|
||||
* ``has_properties`` - match an object that has all of the given properties.
|
||||
* ``has_string`` - match ``str()``
|
||||
* ``instance_of`` - match object type
|
||||
* ``none``, ``not_none`` - match ``None``, or not ``None``
|
||||
* ``same_instance`` - match same object
|
||||
* ``calling, raises`` - wrap a method call and assert that it raises an exception
|
||||
|
||||
* Number
|
||||
|
||||
* ``close_to`` - match number close to a given value
|
||||
* ``greater_than``, ``greater_than_or_equal_to``, ``less_than``,
|
||||
``less_than_or_equal_to`` - match numeric ordering
|
||||
|
||||
* Text
|
||||
|
||||
* ``contains_string`` - match part of a string
|
||||
* ``ends_with`` - match the end of a string
|
||||
* ``equal_to_ignoring_case`` - match the complete string but ignore case
|
||||
* ``equal_to_ignoring_whitespace`` - match the complete string but ignore extra whitespace
|
||||
* ``matches_regexp`` - match a regular expression in a string
|
||||
* ``starts_with`` - match the beginning of a string
|
||||
* ``string_contains_in_order`` - match parts of a string, in relative order
|
||||
|
||||
* Logical
|
||||
|
||||
* ``all_of`` - ``and`` together all matchers
|
||||
* ``any_of`` - ``or`` together all matchers
|
||||
* ``anything`` - match anything, useful in composite matchers when you don't care about a particular value
|
||||
* ``is_not`` - negate the matcher
|
||||
|
||||
* Sequence
|
||||
|
||||
* ``contains`` - exactly match the entire sequence
|
||||
* ``contains_inanyorder`` - match the entire sequence, but in any order
|
||||
* ``has_item`` - match if given item appears in the sequence
|
||||
* ``has_items`` - match if all given items appear in the sequence, in any order
|
||||
* ``is_in`` - match if item appears in the given sequence
|
||||
* ``only_contains`` - match if sequence's items appear in given list
|
||||
* ``empty`` - match if the sequence is empty
|
||||
|
||||
* Dictionary
|
||||
|
||||
* ``has_entries`` - match dictionary with list of key-value pairs
|
||||
* ``has_entry`` - match dictionary containing a key-value pair
|
||||
* ``has_key`` - match dictionary with a key
|
||||
* ``has_value`` - match dictionary with a value
|
||||
|
||||
* Decorator
|
||||
|
||||
* ``calling`` - wrap a callable in a deffered object, for subsequent matching on calling behaviour
|
||||
* ``raises`` - Ensure that a deferred callable raises as expected
|
||||
* ``described_as`` - give the matcher a custom failure description
|
||||
* ``is_`` - decorator to improve readability - see `Syntactic sugar` below
|
||||
|
||||
The arguments for many of these matchers accept not just a matching value, but
|
||||
another matcher, so matchers can be composed for greater flexibility. For
|
||||
example, ``only_contains(less_than(5))`` will match any sequence where every
|
||||
item is less than 5.
|
||||
|
||||
|
||||
Syntactic sugar
|
||||
===============
|
||||
|
||||
PyHamcrest strives to make your tests as readable as possible. For example, the
|
||||
``is_`` matcher is a wrapper that doesn't add any extra behavior to the
|
||||
underlying matcher. The following assertions are all equivalent:
|
||||
|
||||
.. code:: python
|
||||
|
||||
assert_that(theBiscuit, equal_to(myBiscuit))
|
||||
assert_that(theBiscuit, is_(equal_to(myBiscuit)))
|
||||
assert_that(theBiscuit, is_(myBiscuit))
|
||||
|
||||
The last form is allowed since ``is_(value)`` wraps most non-matcher arguments
|
||||
with ``equal_to``. But if the argument is a type, it is wrapped with
|
||||
``instance_of``, so the following are also equivalent:
|
||||
|
||||
.. code:: python
|
||||
|
||||
assert_that(theBiscuit, instance_of(Biscuit))
|
||||
assert_that(theBiscuit, is_(instance_of(Biscuit)))
|
||||
assert_that(theBiscuit, is_(Biscuit))
|
||||
|
||||
*Note that PyHamcrest's ``is_`` matcher is unrelated to Python's ``is``
|
||||
operator. The matcher for object identity is ``same_instance``.*
|
||||
|
||||
|
||||
Writing custom matchers
|
||||
=======================
|
||||
|
||||
PyHamcrest comes bundled with lots of useful matchers, but you'll probably find
|
||||
that you need to create your own from time to time to fit your testing needs.
|
||||
This commonly occurs when you find a fragment of code that tests the same set
|
||||
of properties over and over again (and in different tests), and you want to
|
||||
bundle the fragment into a single assertion. By writing your own matcher you'll
|
||||
eliminate code duplication and make your tests more readable!
|
||||
|
||||
Let's write our own matcher for testing if a calendar date falls on a Saturday.
|
||||
This is the test we want to write:
|
||||
|
||||
.. code:: python
|
||||
|
||||
def testDateIsOnASaturday(self):
|
||||
d = datetime.date(2008, 04, 26)
|
||||
assert_that(d, is_(on_a_saturday()))
|
||||
|
||||
And here's the implementation:
|
||||
|
||||
.. code:: python
|
||||
|
||||
from hamcrest.core.base_matcher import BaseMatcher
|
||||
from hamcrest.core.helpers.hasmethod import hasmethod
|
||||
|
||||
class IsGivenDayOfWeek(BaseMatcher):
|
||||
|
||||
def __init__(self, day):
|
||||
self.day = day # Monday is 0, Sunday is 6
|
||||
|
||||
def _matches(self, item):
|
||||
if not hasmethod(item, 'weekday'):
|
||||
return False
|
||||
return item.weekday() == self.day
|
||||
|
||||
def describe_to(self, description):
|
||||
day_as_string = ['Monday', 'Tuesday', 'Wednesday', 'Thursday',
|
||||
'Friday', 'Saturday', 'Sunday']
|
||||
description.append_text('calendar date falling on ') \
|
||||
.append_text(day_as_string[self.day])
|
||||
|
||||
def on_a_saturday():
|
||||
return IsGivenDayOfWeek(5)
|
||||
|
||||
For our Matcher implementation we implement the ``_matches`` method - which
|
||||
calls the ``weekday`` method after confirming that the argument (which may not
|
||||
be a date) has such a method - and the ``describe_to`` method - which is used
|
||||
to produce a failure message when a test fails. Here's an example of how the
|
||||
failure message looks:
|
||||
|
||||
.. code:: python
|
||||
|
||||
assert_that(datetime.date(2008, 04, 06), is_(on_a_saturday()))
|
||||
|
||||
fails with the message::
|
||||
|
||||
AssertionError:
|
||||
Expected: is calendar date falling on Saturday
|
||||
got: <2008-04-06>
|
||||
|
||||
Let's say this matcher is saved in a module named ``isgivendayofweek``. We
|
||||
could use it in our test by importing the factory function ``on_a_saturday``:
|
||||
|
||||
.. code:: python
|
||||
|
||||
from hamcrest import *
|
||||
import unittest
|
||||
from isgivendayofweek import on_a_saturday
|
||||
|
||||
class DateTest(unittest.TestCase):
|
||||
def testDateIsOnASaturday(self):
|
||||
d = datetime.date(2008, 04, 26)
|
||||
assert_that(d, is_(on_a_saturday()))
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
||||
Even though the ``on_a_saturday`` function creates a new matcher each time it
|
||||
is called, you should not assume this is the only usage pattern for your
|
||||
matcher. Therefore you should make sure your matcher is stateless, so a single
|
||||
instance can be reused between matches.
|
||||
|
||||
|
||||
More resources
|
||||
==============
|
||||
|
||||
* Documentation_
|
||||
* Package_
|
||||
* Sources_
|
||||
* Hamcrest_
|
||||
|
||||
.. _Documentation: http://readthedocs.org/docs/pyhamcrest/en/V1.8.2/
|
||||
.. _Package: http://pypi.python.org/pypi/PyHamcrest
|
||||
.. _Sources: https://github.com/hamcrest/PyHamcrest
|
||||
.. _Hamcrest: http://hamcrest.org
|
||||
|
||||
|
||||
@@ -0,0 +1,353 @@
|
||||
Metadata-Version: 2.0
|
||||
Name: PyHamcrest
|
||||
Version: 1.9.0
|
||||
Summary: Hamcrest framework for matcher objects
|
||||
Home-page: https://github.com/hamcrest/PyHamcrest
|
||||
Author: Chris Rose
|
||||
Author-email: offline@offby1.net
|
||||
License: New BSD
|
||||
Download-URL: http://pypi.python.org/packages/source/P/PyHamcrest/PyHamcrest-1.9.0.tar.gz
|
||||
Keywords: hamcrest matchers pyunit unit test testing unittest unittesting
|
||||
Platform: All
|
||||
Classifier: Development Status :: 5 - Production/Stable
|
||||
Classifier: Environment :: Console
|
||||
Classifier: Intended Audience :: Developers
|
||||
Classifier: License :: OSI Approved :: BSD License
|
||||
Classifier: Natural Language :: English
|
||||
Classifier: Operating System :: OS Independent
|
||||
Classifier: Programming Language :: Python :: 2
|
||||
Classifier: Programming Language :: Python :: 2.7
|
||||
Classifier: Programming Language :: Python :: 3
|
||||
Classifier: Programming Language :: Python :: 3.4
|
||||
Classifier: Programming Language :: Python :: Implementation :: CPython
|
||||
Classifier: Programming Language :: Python :: Implementation :: Jython
|
||||
Classifier: Programming Language :: Python :: Implementation :: PyPy
|
||||
Classifier: Topic :: Software Development
|
||||
Classifier: Topic :: Software Development :: Quality Assurance
|
||||
Classifier: Topic :: Software Development :: Testing
|
||||
Provides: hamcrest
|
||||
Requires-Dist: setuptools
|
||||
Requires-Dist: six
|
||||
|
||||
PyHamcrest
|
||||
==========
|
||||
|
||||
| |docs| |travis| |coveralls| |landscape| |scrutinizer| |codeclimate|
|
||||
| |version| |downloads| |wheel| |supported-versions| |supported-implementations|
|
||||
|
||||
.. |docs| image:: https://readthedocs.org/projects/pyhamcrest/badge/?style=flat
|
||||
:target: https://pyhamcrest.readthedocs.org/
|
||||
:alt: Documentation Status
|
||||
|
||||
.. |travis| image:: http://img.shields.io/travis/hamcrest/PyHamcrest/master.png?style=flat
|
||||
:alt: Travis-CI Build Status
|
||||
:target: https://travis-ci.org/hamcrest/PyHamcrest
|
||||
|
||||
.. |appveyor| image:: https://ci.appveyor.com/api/projects/status/github/hamcrest/PyHamcrest?branch=master
|
||||
:alt: AppVeyor Build Status
|
||||
:target: https://ci.appveyor.com/project/hamcrest/PyHamcrest
|
||||
|
||||
.. |coveralls| image:: http://img.shields.io/coveralls/hamcrest/PyHamcrest/master.png?style=flat
|
||||
:alt: Coverage Status
|
||||
:target: https://coveralls.io/r/hamcrest/PyHamcrest
|
||||
|
||||
.. |landscape| image:: https://landscape.io/github/hamcrest/PyHamcrest/master/landscape.svg?style=flat
|
||||
:target: https://landscape.io/github/hamcrest/PyHamcrest/master
|
||||
:alt: Code Quality Status
|
||||
|
||||
.. |codeclimate| image:: https://codeclimate.com/github/hamcrest/PyHamcrest/badges/gpa.svg
|
||||
:target: https://codeclimate.com/github/hamcrest/PyHamcrest
|
||||
:alt: Code Climate
|
||||
|
||||
.. |version| image:: http://img.shields.io/pypi/v/PyHamcrest.png?style=flat
|
||||
:alt: PyPI Package latest release
|
||||
:target: https://pypi.python.org/pypi/PyHamcrest
|
||||
|
||||
.. |downloads| image:: http://img.shields.io/pypi/dm/PyHamcrest.png?style=flat
|
||||
:alt: PyPI Package monthly downloads
|
||||
:target: https://pypi.python.org/pypi/PyHamcrest
|
||||
|
||||
.. |wheel| image:: https://pypip.in/wheel/PyHamcrest/badge.png?style=flat
|
||||
:alt: PyPI Wheel
|
||||
:target: https://pypi.python.org/pypi/PyHamcrest
|
||||
|
||||
.. |supported-versions| image:: https://pypip.in/py_versions/PyHamcrest/badge.png?style=flat
|
||||
:alt: Supported versions
|
||||
:target: https://pypi.python.org/pypi/PyHamcrest
|
||||
|
||||
.. |supported-implementations| image:: https://pypip.in/implementation/PyHamcrest/badge.png?style=flat
|
||||
:alt: Supported imlementations
|
||||
:target: https://pypi.python.org/pypi/PyHamcrest
|
||||
|
||||
.. |scrutinizer| image:: https://img.shields.io/scrutinizer/g/hamcrest/PyHamcrest/master.png?style=flat
|
||||
:alt: Scrtinizer Status
|
||||
:target: https://scrutinizer-ci.com/g/hamcrest/PyHamcrest/
|
||||
|
||||
|
||||
Introduction
|
||||
============
|
||||
|
||||
PyHamcrest is a framework for writing matcher objects, allowing you to
|
||||
declaratively define "match" rules. There are a number of situations where
|
||||
matchers are invaluable, such as UI validation, or data filtering, but it is in
|
||||
the area of writing flexible tests that matchers are most commonly used. This
|
||||
tutorial shows you how to use PyHamcrest for unit testing.
|
||||
|
||||
When writing tests it is sometimes difficult to get the balance right between
|
||||
overspecifying the test (and making it brittle to changes), and not specifying
|
||||
enough (making the test less valuable since it continues to pass even when the
|
||||
thing being tested is broken). Having a tool that allows you to pick out
|
||||
precisely the aspect under test and describe the values it should have, to a
|
||||
controlled level of precision, helps greatly in writing tests that are "just
|
||||
right." Such tests fail when the behavior of the aspect under test deviates
|
||||
from the expected behavior, yet continue to pass when minor, unrelated changes
|
||||
to the behaviour are made.
|
||||
|
||||
Installation
|
||||
============
|
||||
|
||||
Hamcrest can be installed using the usual Python packaging tools. It depends on
|
||||
distribute, but as long as you have a network connection when you install, the
|
||||
installation process will take care of that for you.
|
||||
|
||||
My first PyHamcrest test
|
||||
========================
|
||||
|
||||
We'll start by writing a very simple PyUnit test, but instead of using PyUnit's
|
||||
``assertEqual`` method, we'll use PyHamcrest's ``assert_that`` construct and
|
||||
the standard set of matchers:
|
||||
|
||||
.. code:: python
|
||||
|
||||
from hamcrest import *
|
||||
import unittest
|
||||
|
||||
class BiscuitTest(unittest.TestCase):
|
||||
def testEquals(self):
|
||||
theBiscuit = Biscuit('Ginger')
|
||||
myBiscuit = Biscuit('Ginger')
|
||||
assert_that(theBiscuit, equal_to(myBiscuit))
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
||||
The ``assert_that`` function is a stylized sentence for making a test
|
||||
assertion. In this example, the subject of the assertion is the object
|
||||
``theBiscuit``, which is the first method parameter. The second method
|
||||
parameter is a matcher for ``Biscuit`` objects, here a matcher that checks one
|
||||
object is equal to another using the Python ``==`` operator. The test passes
|
||||
since the ``Biscuit`` class defines an ``__eq__`` method.
|
||||
|
||||
If you have more than one assertion in your test you can include an identifier
|
||||
for the tested value in the assertion:
|
||||
|
||||
.. code:: python
|
||||
|
||||
assert_that(theBiscuit.getChocolateChipCount(), equal_to(10), 'chocolate chips')
|
||||
assert_that(theBiscuit.getHazelnutCount(), equal_to(3), 'hazelnuts')
|
||||
|
||||
As a convenience, assert_that can also be used to verify a boolean condition:
|
||||
|
||||
.. code:: python
|
||||
|
||||
assert_that(theBiscuit.isCooked(), 'cooked')
|
||||
|
||||
This is equivalent to the ``assert_`` method of unittest.TestCase, but because
|
||||
it's a standalone function, it offers greater flexibility in test writing.
|
||||
|
||||
|
||||
Predefined matchers
|
||||
===================
|
||||
|
||||
PyHamcrest comes with a library of useful matchers:
|
||||
|
||||
* Object
|
||||
|
||||
* ``equal_to`` - match equal object
|
||||
* ``has_length`` - match ``len()``
|
||||
* ``has_property`` - match value of property with given name
|
||||
* ``has_properties`` - match an object that has all of the given properties.
|
||||
* ``has_string`` - match ``str()``
|
||||
* ``instance_of`` - match object type
|
||||
* ``none``, ``not_none`` - match ``None``, or not ``None``
|
||||
* ``same_instance`` - match same object
|
||||
* ``calling, raises`` - wrap a method call and assert that it raises an exception
|
||||
|
||||
* Number
|
||||
|
||||
* ``close_to`` - match number close to a given value
|
||||
* ``greater_than``, ``greater_than_or_equal_to``, ``less_than``,
|
||||
``less_than_or_equal_to`` - match numeric ordering
|
||||
|
||||
* Text
|
||||
|
||||
* ``contains_string`` - match part of a string
|
||||
* ``ends_with`` - match the end of a string
|
||||
* ``equal_to_ignoring_case`` - match the complete string but ignore case
|
||||
* ``equal_to_ignoring_whitespace`` - match the complete string but ignore extra whitespace
|
||||
* ``matches_regexp`` - match a regular expression in a string
|
||||
* ``starts_with`` - match the beginning of a string
|
||||
* ``string_contains_in_order`` - match parts of a string, in relative order
|
||||
|
||||
* Logical
|
||||
|
||||
* ``all_of`` - ``and`` together all matchers
|
||||
* ``any_of`` - ``or`` together all matchers
|
||||
* ``anything`` - match anything, useful in composite matchers when you don't care about a particular value
|
||||
* ``is_not`` - negate the matcher
|
||||
|
||||
* Sequence
|
||||
|
||||
* ``contains`` - exactly match the entire sequence
|
||||
* ``contains_inanyorder`` - match the entire sequence, but in any order
|
||||
* ``has_item`` - match if given item appears in the sequence
|
||||
* ``has_items`` - match if all given items appear in the sequence, in any order
|
||||
* ``is_in`` - match if item appears in the given sequence
|
||||
* ``only_contains`` - match if sequence's items appear in given list
|
||||
* ``empty`` - match if the sequence is empty
|
||||
|
||||
* Dictionary
|
||||
|
||||
* ``has_entries`` - match dictionary with list of key-value pairs
|
||||
* ``has_entry`` - match dictionary containing a key-value pair
|
||||
* ``has_key`` - match dictionary with a key
|
||||
* ``has_value`` - match dictionary with a value
|
||||
|
||||
* Decorator
|
||||
|
||||
* ``calling`` - wrap a callable in a deffered object, for subsequent matching on calling behaviour
|
||||
* ``raises`` - Ensure that a deferred callable raises as expected
|
||||
* ``described_as`` - give the matcher a custom failure description
|
||||
* ``is_`` - decorator to improve readability - see `Syntactic sugar` below
|
||||
|
||||
The arguments for many of these matchers accept not just a matching value, but
|
||||
another matcher, so matchers can be composed for greater flexibility. For
|
||||
example, ``only_contains(less_than(5))`` will match any sequence where every
|
||||
item is less than 5.
|
||||
|
||||
|
||||
Syntactic sugar
|
||||
===============
|
||||
|
||||
PyHamcrest strives to make your tests as readable as possible. For example, the
|
||||
``is_`` matcher is a wrapper that doesn't add any extra behavior to the
|
||||
underlying matcher. The following assertions are all equivalent:
|
||||
|
||||
.. code:: python
|
||||
|
||||
assert_that(theBiscuit, equal_to(myBiscuit))
|
||||
assert_that(theBiscuit, is_(equal_to(myBiscuit)))
|
||||
assert_that(theBiscuit, is_(myBiscuit))
|
||||
|
||||
The last form is allowed since ``is_(value)`` wraps most non-matcher arguments
|
||||
with ``equal_to``. But if the argument is a type, it is wrapped with
|
||||
``instance_of``, so the following are also equivalent:
|
||||
|
||||
.. code:: python
|
||||
|
||||
assert_that(theBiscuit, instance_of(Biscuit))
|
||||
assert_that(theBiscuit, is_(instance_of(Biscuit)))
|
||||
assert_that(theBiscuit, is_(Biscuit))
|
||||
|
||||
*Note that PyHamcrest's ``is_`` matcher is unrelated to Python's ``is``
|
||||
operator. The matcher for object identity is ``same_instance``.*
|
||||
|
||||
|
||||
Writing custom matchers
|
||||
=======================
|
||||
|
||||
PyHamcrest comes bundled with lots of useful matchers, but you'll probably find
|
||||
that you need to create your own from time to time to fit your testing needs.
|
||||
This commonly occurs when you find a fragment of code that tests the same set
|
||||
of properties over and over again (and in different tests), and you want to
|
||||
bundle the fragment into a single assertion. By writing your own matcher you'll
|
||||
eliminate code duplication and make your tests more readable!
|
||||
|
||||
Let's write our own matcher for testing if a calendar date falls on a Saturday.
|
||||
This is the test we want to write:
|
||||
|
||||
.. code:: python
|
||||
|
||||
def testDateIsOnASaturday(self):
|
||||
d = datetime.date(2008, 04, 26)
|
||||
assert_that(d, is_(on_a_saturday()))
|
||||
|
||||
And here's the implementation:
|
||||
|
||||
.. code:: python
|
||||
|
||||
from hamcrest.core.base_matcher import BaseMatcher
|
||||
from hamcrest.core.helpers.hasmethod import hasmethod
|
||||
|
||||
class IsGivenDayOfWeek(BaseMatcher):
|
||||
|
||||
def __init__(self, day):
|
||||
self.day = day # Monday is 0, Sunday is 6
|
||||
|
||||
def _matches(self, item):
|
||||
if not hasmethod(item, 'weekday'):
|
||||
return False
|
||||
return item.weekday() == self.day
|
||||
|
||||
def describe_to(self, description):
|
||||
day_as_string = ['Monday', 'Tuesday', 'Wednesday', 'Thursday',
|
||||
'Friday', 'Saturday', 'Sunday']
|
||||
description.append_text('calendar date falling on ') \
|
||||
.append_text(day_as_string[self.day])
|
||||
|
||||
def on_a_saturday():
|
||||
return IsGivenDayOfWeek(5)
|
||||
|
||||
For our Matcher implementation we implement the ``_matches`` method - which
|
||||
calls the ``weekday`` method after confirming that the argument (which may not
|
||||
be a date) has such a method - and the ``describe_to`` method - which is used
|
||||
to produce a failure message when a test fails. Here's an example of how the
|
||||
failure message looks:
|
||||
|
||||
.. code:: python
|
||||
|
||||
assert_that(datetime.date(2008, 04, 06), is_(on_a_saturday()))
|
||||
|
||||
fails with the message::
|
||||
|
||||
AssertionError:
|
||||
Expected: is calendar date falling on Saturday
|
||||
got: <2008-04-06>
|
||||
|
||||
Let's say this matcher is saved in a module named ``isgivendayofweek``. We
|
||||
could use it in our test by importing the factory function ``on_a_saturday``:
|
||||
|
||||
.. code:: python
|
||||
|
||||
from hamcrest import *
|
||||
import unittest
|
||||
from isgivendayofweek import on_a_saturday
|
||||
|
||||
class DateTest(unittest.TestCase):
|
||||
def testDateIsOnASaturday(self):
|
||||
d = datetime.date(2008, 04, 26)
|
||||
assert_that(d, is_(on_a_saturday()))
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
||||
Even though the ``on_a_saturday`` function creates a new matcher each time it
|
||||
is called, you should not assume this is the only usage pattern for your
|
||||
matcher. Therefore you should make sure your matcher is stateless, so a single
|
||||
instance can be reused between matches.
|
||||
|
||||
|
||||
More resources
|
||||
==============
|
||||
|
||||
* Documentation_
|
||||
* Package_
|
||||
* Sources_
|
||||
* Hamcrest_
|
||||
|
||||
.. _Documentation: http://readthedocs.org/docs/pyhamcrest/en/V1.8.2/
|
||||
.. _Package: http://pypi.python.org/pypi/PyHamcrest
|
||||
.. _Sources: https://github.com/hamcrest/PyHamcrest
|
||||
.. _Hamcrest: http://hamcrest.org
|
||||
|
||||
|
||||
@@ -0,0 +1,120 @@
|
||||
hamcrest/__init__.py,sha256=Uo0mxeePyXP9_yIzBBvKqIL6tzEHqBwBO1eSHfAKies,230
|
||||
hamcrest/core/__init__.py,sha256=nDkYm1E1P7XpHmR8EHu17eahlmC6uYix4HurTyJjhlE,230
|
||||
hamcrest/core/assert_that.py,sha256=mPdTQQVsjUliK3xp8l_Vn3YmMzg_h5rYhWJk2mstMc0,2428
|
||||
hamcrest/core/base_description.py,sha256=auvrelro2vGh_A05TQxwbaBJStvfHiFqm0TL56luxEU,2841
|
||||
hamcrest/core/base_matcher.py,sha256=eRhLv7zFBJGaz68vEsDlvKbrWwU8GRDfZc7pWBNcxwI,1193
|
||||
hamcrest/core/compat.py,sha256=wUi1u_nIhgUA3kFGJDZLQ2D_cRw79E1SxPDMaI4mzG0,642
|
||||
hamcrest/core/description.py,sha256=gbVS-ejZJ783o-WEA66bXnXc9DH5cOlQXg0FlzoVGro,1729
|
||||
hamcrest/core/matcher.py,sha256=BG6e8bIJvwFI0qkaSkt_SOuuLI0VidvoX8GQLadYssU,1851
|
||||
hamcrest/core/selfdescribing.py,sha256=RzwqHRGg00AJYweGiP8JzSxoHFdBo0Q7m5axYfutfG8,574
|
||||
hamcrest/core/selfdescribingvalue.py,sha256=OpGLOjdPA9FSgmLZzmkfYrDvpG261TDDiM56muROFqQ,834
|
||||
hamcrest/core/string_description.py,sha256=Jp-SbuY8LAwPucL4NMrwWqRhkg6CMwYE-pH0ZDMUq8A,908
|
||||
hamcrest/core/core/__init__.py,sha256=7q_pNO9cmtV3BEixiGcueNdbxRxlKEFZ1RSO-5GP58E,770
|
||||
hamcrest/core/core/allof.py,sha256=x2ea18Z5cioRybs1heTd3E8zYtpFbuBJg3vIU3vl9k0,1487
|
||||
hamcrest/core/core/anyof.py,sha256=8j2KAsaToXbv8CA5hed4bqPR3hscODIiaFhAlAyJ2Vs,1097
|
||||
hamcrest/core/core/described_as.py,sha256=kyy_qRpoebWB1bS2ReAkNDt-79iXu6HqHxOG0GT7PtQ,1623
|
||||
hamcrest/core/core/is_.py,sha256=C7UCASfr4AIlaaMZnT5d34OthAZQ3rYv8OhszQjz-Eg,2547
|
||||
hamcrest/core/core/isanything.py,sha256=D2QO5dbDhwlVRGLFrnxOSijTyeKN2iWLRwjpvnumkvg,798
|
||||
hamcrest/core/core/isequal.py,sha256=TAwF_lWIjVokPruXN8IGS6ajzPGlThanTLPdhktKwRQ,893
|
||||
hamcrest/core/core/isinstanceof.py,sha256=dnt8YKLhYwGZvDkJ0OTdLd1PN9cB9ZWCg5k8kdnEuqI,1352
|
||||
hamcrest/core/core/isnone.py,sha256=51ueQKBgg0RzWVLzjFOyt6K0ejk2EbXUlUX90ORPm80,557
|
||||
hamcrest/core/core/isnot.py,sha256=_z_ynAVUXEUGWoiRlynFa_yaCVh9cK9LIOznDfKVZeo,1533
|
||||
hamcrest/core/core/issame.py,sha256=8FvAjud4HTuyz7O-XoJbzLtKhChCr1_5JmzMYMeQt1s,1261
|
||||
hamcrest/core/core/raises.py,sha256=BZXtMlQiEqEjQMYT76HUiuQNRjTECIUmL82_FKYhAvs,3610
|
||||
hamcrest/core/helpers/__init__.py,sha256=mPsycYI18LoGawOo9BfETa7yKtnM-fDjFOr43BIevUg,146
|
||||
hamcrest/core/helpers/hasmethod.py,sha256=LPh_WDRuyKYII3G3fX_x2Ql-ECuPJn4tK5eWMLbetLg,325
|
||||
hamcrest/core/helpers/wrap_matcher.py,sha256=IQTtw98Pp1NXcVTy9boaNh6jayvawKHhX62R3ZwnVwQ,880
|
||||
hamcrest/library/__init__.py,sha256=2atNiBCC2g3c-7jw53CltNgU4wEao1uRcheUPl1ML50,1014
|
||||
hamcrest/library/collection/__init__.py,sha256=iJU6WCsf0R22m11fqMA9Ztb161AZAdrsKG-4Cj38lZ0,635
|
||||
hamcrest/library/collection/is_empty.py,sha256=p3-B7DCmdbVzqiW3D1h3krdeqmu9B0mfYOaa6HehODg,913
|
||||
hamcrest/library/collection/isdict_containing.py,sha256=6QxDtDp_Z2TK-6om8cHnJDh45YdmaNHAEy5n97rzf00,2056
|
||||
hamcrest/library/collection/isdict_containingentries.py,sha256=xKtdFjrwLN32rUdRR4PBUSYa3yACa6jXsmlZv0D9YAU,5168
|
||||
hamcrest/library/collection/isdict_containingkey.py,sha256=aiBpusjpZmkUEMZ_rUFZBB1GxIfsqluMjhXoWNScqZY,1535
|
||||
hamcrest/library/collection/isdict_containingvalue.py,sha256=N7mHKgMnd7q6HsQekHH6DShNYbLiSXN9cpQgcdMIjlw,1565
|
||||
hamcrest/library/collection/isin.py,sha256=bcVslW0fUq0pM_SrT9gdltTlNfeJkrVPZAlg6riV2Ys,774
|
||||
hamcrest/library/collection/issequence_containing.py,sha256=ZwYMm2-Ul_JtvjcgdMjipYdz82yUbGmRNsdPAjO9RX0,3001
|
||||
hamcrest/library/collection/issequence_containinginanyorder.py,sha256=Px_W2-_0XDOXiL2NTTMp16ZTZvBl4m5rXjlMoR4Ulmw,3613
|
||||
hamcrest/library/collection/issequence_containinginorder.py,sha256=x7AT_kOCaPY0LmZw28ln8xLLHBtT-I3NneoCWzMJoYA,3219
|
||||
hamcrest/library/collection/issequence_onlycontaining.py,sha256=Ia17P1HVgb43lZfdUEhmPyUUUWtGLix__fqXIQJTUiI,1626
|
||||
hamcrest/library/integration/__init__.py,sha256=3aiupojVacPksKTXVhqRs9OwUDoUlUw-bjWItJnRg8Q,254
|
||||
hamcrest/library/integration/match_equality.py,sha256=0BMth20YLTqjqTLT4qMVldAe2dQV3CJ2j3zLXDIGl9c,1192
|
||||
hamcrest/library/number/__init__.py,sha256=J3UoFdR9UPq9zXSKe1a9qAlpjaVst8-pnaxsvbCPj78,335
|
||||
hamcrest/library/number/iscloseto.py,sha256=2lQTw3Xvo5MW-aePxpWVUOwyV_ydXtH6cCAIAxeopk8,2259
|
||||
hamcrest/library/number/ordering_comparison.py,sha256=8XxVSOzPK29D14h4wtBZYVYKZf6IcABaQEKihEuzlhI,1700
|
||||
hamcrest/library/object/__init__.py,sha256=pxzCpybBHRaIg7RJUAw7R1Po0llw8QBbVv_R1TXNBhc,319
|
||||
hamcrest/library/object/haslength.py,sha256=mpYVvrBZV548FwEeqlHWYofv9LPgChvnypZ4RhZDMp0,1681
|
||||
hamcrest/library/object/hasproperty.py,sha256=9t8upZxjqSQp6IvGyTm4ftGvcpBeyk0dy36HgvlXZBg,5740
|
||||
hamcrest/library/object/hasstring.py,sha256=_Ht1x-DwV4hk2fRuGo_KoayoLOIoWObKoA30u7HnABU,1250
|
||||
hamcrest/library/text/__init__.py,sha256=3Uuy1lY2p0VEUy1SAIO6IZgDDgyx8ZsB98k-J2FA_R0,548
|
||||
hamcrest/library/text/isequal_ignoring_case.py,sha256=VGkR3PNDOVE1MJT9H4a3SjR2SIYNzT80VoV6NEq3aqw,1257
|
||||
hamcrest/library/text/isequal_ignoring_whitespace.py,sha256=NQzswc7fk5rOhcoHO4zbYSWqn-WQdQ7Hwf0FoDHAwBM,1667
|
||||
hamcrest/library/text/stringcontains.py,sha256=JbkSxdFkpRrNYJfSUghboxe1jRLfHAJvOn6PYvMx7fQ,953
|
||||
hamcrest/library/text/stringcontainsinorder.py,sha256=B3qG7TG24_WyVPGJER2iqi7fzOMZN0UsBRJPtWutBkc,1705
|
||||
hamcrest/library/text/stringendswith.py,sha256=JjukJWSVWgURvTstrbCGCQdQzY0PMWLul__UlDh2NGA,980
|
||||
hamcrest/library/text/stringmatches.py,sha256=AEBn8NI3q-YzRUdXiAfnw1Kmse-LLxJUluDAuy_D9nU,1151
|
||||
hamcrest/library/text/stringstartswith.py,sha256=oOro8G3z8nAOUyOjHHkHhUvY-lt7XRTJzDr9dYxxons,1007
|
||||
hamcrest/library/text/substringmatcher.py,sha256=lSPxE7pTpTJlUkMtd28WgsM1FFm56JVZixSvAldSZXk,695
|
||||
PyHamcrest-1.9.0.dist-info/DESCRIPTION.rst,sha256=13XTDh2baR2aJ91v_lAOjEXD7Ydush_RHhk0Z3azfs8,11973
|
||||
PyHamcrest-1.9.0.dist-info/METADATA,sha256=s0naXZHUZhft0MWcUeZVaZYlREKPOqHp3mUQrhUoC6s,13276
|
||||
PyHamcrest-1.9.0.dist-info/metadata.json,sha256=Jqs-ZSW5kWSnfvxDsRMwSQH6TxEqSJjBJWiQk1G-c_A,1545
|
||||
PyHamcrest-1.9.0.dist-info/pbr.json,sha256=jdAcCmfO0nnMs9-YKXuwDyKnxc4qGwyUxyGulF9Pam4,47
|
||||
PyHamcrest-1.9.0.dist-info/RECORD,,
|
||||
PyHamcrest-1.9.0.dist-info/top_level.txt,sha256=mRc0yPsPQSqFgWBmZBY33u-05Xtm5M4GEve4NjYdloQ,9
|
||||
PyHamcrest-1.9.0.dist-info/WHEEL,sha256=AvR0WeTpDaxT645bl5FQxUK6NPsTls2ttpcGJg3j1Xg,110
|
||||
PyHamcrest-1.9.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
|
||||
hamcrest/core/core/__pycache__/issame.cpython-37.pyc,,
|
||||
hamcrest/core/core/__pycache__/isinstanceof.cpython-37.pyc,,
|
||||
hamcrest/core/core/__pycache__/raises.cpython-37.pyc,,
|
||||
hamcrest/core/core/__pycache__/is_.cpython-37.pyc,,
|
||||
hamcrest/core/core/__pycache__/isanything.cpython-37.pyc,,
|
||||
hamcrest/core/core/__pycache__/isnone.cpython-37.pyc,,
|
||||
hamcrest/core/core/__pycache__/isnot.cpython-37.pyc,,
|
||||
hamcrest/core/core/__pycache__/anyof.cpython-37.pyc,,
|
||||
hamcrest/core/core/__pycache__/allof.cpython-37.pyc,,
|
||||
hamcrest/core/core/__pycache__/__init__.cpython-37.pyc,,
|
||||
hamcrest/core/core/__pycache__/described_as.cpython-37.pyc,,
|
||||
hamcrest/core/core/__pycache__/isequal.cpython-37.pyc,,
|
||||
hamcrest/core/__pycache__/string_description.cpython-37.pyc,,
|
||||
hamcrest/core/__pycache__/base_matcher.cpython-37.pyc,,
|
||||
hamcrest/core/__pycache__/compat.cpython-37.pyc,,
|
||||
hamcrest/core/__pycache__/assert_that.cpython-37.pyc,,
|
||||
hamcrest/core/__pycache__/selfdescribing.cpython-37.pyc,,
|
||||
hamcrest/core/__pycache__/selfdescribingvalue.cpython-37.pyc,,
|
||||
hamcrest/core/__pycache__/matcher.cpython-37.pyc,,
|
||||
hamcrest/core/__pycache__/base_description.cpython-37.pyc,,
|
||||
hamcrest/core/__pycache__/description.cpython-37.pyc,,
|
||||
hamcrest/core/__pycache__/__init__.cpython-37.pyc,,
|
||||
hamcrest/core/helpers/__pycache__/hasmethod.cpython-37.pyc,,
|
||||
hamcrest/core/helpers/__pycache__/wrap_matcher.cpython-37.pyc,,
|
||||
hamcrest/core/helpers/__pycache__/__init__.cpython-37.pyc,,
|
||||
hamcrest/library/collection/__pycache__/issequence_containinginanyorder.cpython-37.pyc,,
|
||||
hamcrest/library/collection/__pycache__/issequence_containing.cpython-37.pyc,,
|
||||
hamcrest/library/collection/__pycache__/issequence_containinginorder.cpython-37.pyc,,
|
||||
hamcrest/library/collection/__pycache__/isdict_containingentries.cpython-37.pyc,,
|
||||
hamcrest/library/collection/__pycache__/isdict_containing.cpython-37.pyc,,
|
||||
hamcrest/library/collection/__pycache__/isdict_containingkey.cpython-37.pyc,,
|
||||
hamcrest/library/collection/__pycache__/is_empty.cpython-37.pyc,,
|
||||
hamcrest/library/collection/__pycache__/issequence_onlycontaining.cpython-37.pyc,,
|
||||
hamcrest/library/collection/__pycache__/isin.cpython-37.pyc,,
|
||||
hamcrest/library/collection/__pycache__/isdict_containingvalue.cpython-37.pyc,,
|
||||
hamcrest/library/collection/__pycache__/__init__.cpython-37.pyc,,
|
||||
hamcrest/library/integration/__pycache__/match_equality.cpython-37.pyc,,
|
||||
hamcrest/library/integration/__pycache__/__init__.cpython-37.pyc,,
|
||||
hamcrest/library/__pycache__/__init__.cpython-37.pyc,,
|
||||
hamcrest/library/number/__pycache__/ordering_comparison.cpython-37.pyc,,
|
||||
hamcrest/library/number/__pycache__/__init__.cpython-37.pyc,,
|
||||
hamcrest/library/number/__pycache__/iscloseto.cpython-37.pyc,,
|
||||
hamcrest/library/object/__pycache__/hasstring.cpython-37.pyc,,
|
||||
hamcrest/library/object/__pycache__/haslength.cpython-37.pyc,,
|
||||
hamcrest/library/object/__pycache__/hasproperty.cpython-37.pyc,,
|
||||
hamcrest/library/object/__pycache__/__init__.cpython-37.pyc,,
|
||||
hamcrest/library/text/__pycache__/stringendswith.cpython-37.pyc,,
|
||||
hamcrest/library/text/__pycache__/stringmatches.cpython-37.pyc,,
|
||||
hamcrest/library/text/__pycache__/stringstartswith.cpython-37.pyc,,
|
||||
hamcrest/library/text/__pycache__/substringmatcher.cpython-37.pyc,,
|
||||
hamcrest/library/text/__pycache__/stringcontainsinorder.cpython-37.pyc,,
|
||||
hamcrest/library/text/__pycache__/isequal_ignoring_whitespace.cpython-37.pyc,,
|
||||
hamcrest/library/text/__pycache__/stringcontains.cpython-37.pyc,,
|
||||
hamcrest/library/text/__pycache__/isequal_ignoring_case.cpython-37.pyc,,
|
||||
hamcrest/library/text/__pycache__/__init__.cpython-37.pyc,,
|
||||
hamcrest/__pycache__/__init__.cpython-37.pyc,,
|
||||
@@ -0,0 +1,6 @@
|
||||
Wheel-Version: 1.0
|
||||
Generator: bdist_wheel (0.24.0)
|
||||
Root-Is-Purelib: true
|
||||
Tag: py2-none-any
|
||||
Tag: py3-none-any
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
{"license": "New BSD", "download_url": "http://pypi.python.org/packages/source/P/PyHamcrest/PyHamcrest-1.9.0.tar.gz", "name": "PyHamcrest", "provides": "hamcrest", "test_requires": [{"requires": ["hypothesis (>=1.11)", "pytest (>=2.8)", "mock", "pytest-cov"]}], "extensions": {"python.details": {"project_urls": {"Home": "https://github.com/hamcrest/PyHamcrest"}, "contacts": [{"name": "Chris Rose", "role": "author", "email": "offline@offby1.net"}], "document_names": {"description": "DESCRIPTION.rst"}}}, "run_requires": [{"requires": ["setuptools", "six"]}], "generator": "bdist_wheel (0.24.0)", "summary": "Hamcrest framework for matcher objects", "extras": [], "classifiers": ["Development Status :: 5 - Production/Stable", "Environment :: Console", "Intended Audience :: Developers", "License :: OSI Approved :: BSD License", "Natural Language :: English", "Operating System :: OS Independent", "Programming Language :: Python :: 2", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.4", "Programming Language :: Python :: Implementation :: CPython", "Programming Language :: Python :: Implementation :: Jython", "Programming Language :: Python :: Implementation :: PyPy", "Topic :: Software Development", "Topic :: Software Development :: Quality Assurance", "Topic :: Software Development :: Testing"], "version": "1.9.0", "metadata_version": "2.0", "keywords": ["hamcrest", "matchers", "pyunit", "unit", "test", "testing", "unittest", "unittesting"], "platform": "All"}
|
||||
Reference in New Issue
Block a user