{ "info": { "author": "Martin Aspeli", "author_email": "optilude@gmail.com", "bugtrack_url": null, "classifiers": [ "Programming Language :: Python" ], "description": "CoreJet\n=======\n\nCoreJet is a Behaviour Driven Testing specification and approach, with\nimplementations in Python and Java. See http://corejet.org for more details.\n\nThis package provides core CoreJet functionality in Python. You will probably\nalso be interested in `corejet.testrunner` and possibly `corejet.jira`_.\n\nWhy not Cucumber?\n-----------------\n\nThere are various packages that implement a similar style of BDD testing in\nPython, usually based on `Cucumber`_. CoreJet has one important philosophical\ndifference: Instead of writing stories and scenarios in plain text files,\nthey are intended to be managed as part of a requirements management system\nsuch as JIRA (hence `corejet.jira`_). This manages epics, stories and\nscenarios, as well as the lifecycle and metadata surrounding requirements:\nwhether they are open or closed, how big (in story points) they are, and how\nvaluable they are to business users (priority).\n\nA \"requirements catalogue source\" extracts them from this system into either\nan intermediary XML format (see below) or directly into the CoreJet data\nmodel (again, see below). The test runner (`corejet.testrunner`_) first\nfetches the current requirements catalogue, then executes all CoreJet tests,\nmatching up stories (by id) and scenarios (by name) and setting the status\nof each to either \"pass\", \"fail\", \"pending\" (not yet implemented) or\n\"mismatch\" (a given/when/then step in a scenario is out of sync with the\nrequirements management system).\n\nThe output of this analysis is written to an augmented CoreJet XML file. This\nis then used to generate a visualisation of the state of the project (see\n`corejet.visualization`_), with colour coding to indicate how much of the\nproject is in fact complete, where \"complete\" means it has passing automated\ntests that accurately represent the business' acceptance criteria.\n\nInstallation\n============\n\nYou can install ``corejet.core`` as a dependency of your package, e.g. in\n``setup.py`` adding::\n\n install_requires=['corejet.core']\n\nor, if you prefer to keep your tests in an extra::\n\n extras_require = {'test': ['corejet.core']}\n\nNote however that ``corejet.core`` relies on the `lxml`_ library. This is\nsometimes a bit tricky to install on OS X and older Linux platforms. If you\nare using Buildout to install your packages, you may want to use\n``z3c.recipe.lxml`` to install ``lxml``: Add ``lxml`` as the *first* item\nin your ``parts`` list and then add this section::\n\n [lxml]\n recipe = z3c.recipe.staticlxml\n egg = lxml\n\nTest syntax\n===========\n\nTo write CoreJet tests in Python, you can use the decorators found in this\npackage in combination with ``unittest`` style test cases. To do this, you\nshould depend on ``corejet.core`` in your own package (or at least in its\nlist of test dependencies), and probably also ``unittest2`` if working in\nPython 2.6 or earlier.\n\nHere is an example::\n\n import unittest2 as unittest\n from corejet.core import Scenario, story, scenario, given, when, then\n\n @story(id=\"S1\", title=\"As a user, I can log in\")\n class Login(unittest.TestCase):\n\n @scenario(\"Invalid username\")\n class InvalidUsername(Scenario):\n\n @given(\"A user 'joebloggs' with password 'secret'\")\n def setupUser(self):\n # Some precondition logic, e.g.\n createUser('jobloggs', 'secret')\n\n @when(\"Entering the username 'jobloggs' and password 'secret'\")\n def attemptLogin(self):\n # Call some action logic, e.g.\n loginAs('jobloggs', 'secret')\n\n @then(\"An error is shown\")\n def checkOutput(self):\n # Perform some assertion, e.g.\n errorMessages = getErrorMessages()\n self.assertTrue(\"Invalid username\" in errorMessages)\n\n @scenario(\"Invalid password\")\n class InvalidPassword(Scenario):\n\n @given(\"A user 'joebloggs' with password 'secret'\")\n def setupUser(self):\n # Some precondition logic, e.g.\n createUser('jobloggs', 'secret')\n\n @when(\"Entering the username 'joebloggs' and password 'uhoh'\")\n def attemptLogin(self):\n # Call some action logic, e.g.\n loginAs('joebloggs', 'uhph')\n\n @then(\"An error is shown\")\n def checkOutput(self):\n # Perform some assertion, e.g.\n errorMessages = getErrorMessages()\n self.assertTrue(\"Invalid password\" in errorMessages)\n\nYou can have as many or as few scenarios as you want. The ``Scenario`` base\nclass provides access to an attribute ``self.story``, which is an instance of\nthe outer ``@story``-annotated test case class. This allows access to shared\nattributes or state. You can also use standard ``unittest `` conventions like\n``setUp()`` and ``tearDown()`` on the outer class (but not on the ``Scenario``\nclasses) to manage your test fixtures.\n\nIn fact, at runtime, each inner scenario class is turned into a standard\nmethod on the outer story class with the name ``test_()``,\nwhich, when called, will call each of the ``@given``-annotated methods in the\ninner class, then each of the ``@when``-annotated methods, then each of the\n``@then``-annotated methods.\n\nThe reason for this trick is to ensure standard test collectors work. In fact,\na CoreJet test should work with any standard testrunner that can execute\n``unittest`` tests.\n\nOf course, the main reason to use CoreJet is to generate a report of completed\nfunctional coverage. To do this, you can use the test runner in\n`corejet.testrunner`_ combined with a requirements catalogue source. See that\npackage for details.\n\nData model\n==========\n\nThe standard CoreJet data model is represented in this package in the\nmodule ``corejet.core.model``, and described by the interfaces in\n``corejet.core.interfaces``. There main class is the\n``RequirementsCatalogue``, which contains a list of ``Epic`` object, which in\nturn contain a list of ``Story`` objects, which in turn contain a list of\n``Scenario`` objects, which in turn contain three lists (given, when and then)\nof ``Step`` objects.\n\nSee the documentation in the source for more details.\n\nXML parsing and serialization\n-----------------------------\n\nThe ``RequirementsCatalog`` class provides methods ``populate()`` and\n``write()``, which can read and write, respectively, a standard CoreJet XML\nfile to initialise or serialise the catalogue.\n\nHere is an example file for the one story and and two scenarios above,\ncontained in a fictitious epic::\n\n \n \n \n \n A user 'joebloggs' with password 'secret'\n Entering the username 'jobloggs' and password 'secret'\n An error is shown\n \n \n A user 'joebloggs' with password 'secret'\n Entering the username 'joebloggs' and password 'uhoh'\n An error is shown\n \n \n \n \n\nScenario parser\n===============\n\nScenarios are often written in \"Gherkin\" syntax (as per the Cucumber\nframework, form which CoreJet is partly inspired).\n\nScenarios can be written in plain text like so::\n\n Scenario: Invalid username\n Given A user 'joebloggs' with password 'secret'\n When Entering the username 'jobloggs' and password 'secret'\n Then An error is shown\n\n Scenario: Invalid password\n Given A user 'joebloggs' with password 'secret'\n When Entering the username 'joebloggs' and password 'uhoh'\n Then An error is shown\n\n Scenario: Cancel button\n Given A user 'joebloggs' with password 'secret'\n When Entering the username 'joebloggs' and password 'uhoh'\n And Clicking the 'cancel' button\n Then The user is taken away from the page\n And A warning is shown\n\nScenarios may be preceded by a background description composed of one or more\n\"Given\" clauses affecting every scenario::\n\n Given I'm logged in\n And I've got superuser privileges\n\n Scenario: ...\n\nIn addition, there is basic support for \"Scenario Outline\" with \"Examples\".\n\nThe full Gherkin syntax is more involved, but to parse this simplified style\nof scenarios and append them to a story, you can use the function\n``corejet.core.parser.appendScenarios``. It takes a ``Story`` and a string\ncontaining the acceptance criteria text as its two arguments.\n\nThe parser is relatively forgiving, but note:\n\n * The parser is case-insensitive\n * Zero or more scenarios may be present\n * Scenarios must start with \"Scenario: \" followed by a name\n * The \"Given\" clause is optional, but must come first in a scenario\n * The \"When\" clause is required, and must come before the \"Then\" clause\n * The \"Then\"\" clause is also required\n * An \"And\" or \"But\" clause can come after any \"Given\", \"When\" or \"Then\", but\n not first.\n\nGenerating test skeletons\n=========================\n\n``corejet.core`` ships with an XSLT stylesheet for generating test skeletons\nfor Python unittest. If you are using buildout, you can install a helper\nscript for executing the XSLT-transformation with::\n\n [corejet2py]\n recipe = zc.recipe.rgg\n eggs = corejet.core\n scripts = corejet2py\n\nAnd execute it with::\n\n bin/corejet2py path/to/corejet.xml\n\nTry ``bin/corejet2py --help`` for more information.\n\n.. _corejet.recipe.testrunner: http://pypi.python.org/pypi/corejet.recipe.testrunner\n.. _corejet.testrunner: http://pypi.python.org/pypi/corejet.testrunner\n.. _corejet.jira: http://pypi.python.org/pypi/corejet.jira\n.. _corejet.visualization: http://pypi.python.org/pypi/corejet.visualization\n.. _lxml: http://lxml.de\n.. _Cucumber: http://cukes.info\n\nChangelog\n=========\n\n\n1.1.0 (2016-08-26)\n------------------\n\n- Fix to run with python-dateutil >= 2.0devw\n [datakurre]\n\n\n1.0.2 (2012-05-30)\n------------------\n\n- Fixed test skeleton generation XSLT to strip extra whitespaces.\n [datakurre]\n\n\n1.0.1 (2012-05-27)\n------------------\n\n- Added helper script for generating test skeletons from test reports.\n Added 'argparse' into requirements.\n [datakurre]\n\n\n1.0.0\n-----\n\n- Added Finnish language support ('# language: fi')\n [datakurre]\n- Added parser support for Cucumber-like 'language' keyword\n [datakurre]\n- Added parser support for 'Scenario Outline' and 'Examples'\n [datakurre]\n- Added new step keyword *but* as on alias to *and*\n [datakurre]\n- Modified decorators to name test modules and methods by normalizing\n their respective titles\n [datakurre]\n- Completed support for story-level steps\n [datakurre]\n- Ensure quotes (\") are converted into apostrophes (')\n [datakurre]\n- Fixed corejet-to-python.xsl to produce runnable test skeletons\n [datakurre]\n\n\n1.0a4\n-----\n\n- Ensure multiple steps of the same type always execute in the right sequence.\n [optilude]\n\n\n1.0a3\n-----\n\n- Fix broken package\n [optilude]\n\n\n1.0a1\n-----\n\n- First release\n [optilude]", "description_content_type": null, "docs_url": null, "download_url": "", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "http://corejet.org", "keywords": "corejet zope.testing", "license": "ZPL 2.1", "maintainer": "", "maintainer_email": "", "name": "corejet.core", "package_url": "https://pypi.org/project/corejet.core/", "platform": "UNKNOWN", "project_url": "https://pypi.org/project/corejet.core/", "project_urls": { "Homepage": "http://corejet.org" }, "release_url": "https://pypi.org/project/corejet.core/1.1.0/", "requires_dist": null, "requires_python": "", "summary": "Defines test infrastructure for building CoreJet tests", "version": "1.1.0" }, "last_serial": 2305532, "releases": { "1.0.0": [ { "comment_text": "", "digests": { "md5": "6a8d8731db6e7c9fe1e0d9ef3c1a162b", "sha256": "ecf38ff212a730c831774250681c45a6d6e138a70ef2216e6d6403ec3a26a946" }, "downloads": -1, "filename": "corejet.core-1.0.0.zip", "has_sig": false, "md5_digest": "6a8d8731db6e7c9fe1e0d9ef3c1a162b", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 35888, "upload_time": "2012-05-26T15:40:04", "url": "https://files.pythonhosted.org/packages/52/a5/05147448979679b94dda7795b59acd8decbe306592d5c195dcb18753130f/corejet.core-1.0.0.zip" } ], "1.0.1": [ { "comment_text": "", "digests": { "md5": "4b68bfebe59a2298faa31081b6842de8", "sha256": "8b5e9f5f032a691b0c5522b3d66f2ffc0a9766f889451b2e9576a55992189ffd" }, "downloads": -1, "filename": "corejet.core-1.0.1.zip", "has_sig": false, "md5_digest": "4b68bfebe59a2298faa31081b6842de8", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 38007, "upload_time": "2012-05-27T11:23:46", "url": "https://files.pythonhosted.org/packages/2b/7f/4b730b000143787b874ee3a2df539b1cd64017eabc7f1bb1459d06e60180/corejet.core-1.0.1.zip" } ], "1.0.2": [ { "comment_text": "", "digests": { "md5": "fac95fcbf9789d5d423a41341c5cfb00", "sha256": "aa808d34a57025b43fd81c91e6aee12c3b0bfdcf3748f2f877f07c7e349d02ad" }, "downloads": -1, "filename": "corejet.core-1.0.2.zip", "has_sig": false, "md5_digest": "fac95fcbf9789d5d423a41341c5cfb00", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 38168, "upload_time": "2012-05-30T04:26:21", "url": "https://files.pythonhosted.org/packages/ca/2b/dc65824cdf93fd54bade5872ded03046d2191c960b0c7bb953362e27e760/corejet.core-1.0.2.zip" } ], "1.0a1": [ { "comment_text": "", "digests": { "md5": "0364fb28bf06fe756955cd46ebc7989b", "sha256": "42f35cabb35c47f2e7e358f21de472cf763829f397482c5a686b5c363a7fa7bf" }, "downloads": -1, "filename": "corejet.core-1.0a1.tar.gz", "has_sig": false, "md5_digest": "0364fb28bf06fe756955cd46ebc7989b", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 11806, "upload_time": "2011-05-16T02:04:42", "url": "https://files.pythonhosted.org/packages/b5/63/ac71b2e631afbcbbe4fd5caab43491e621d7ab910c9434f5eccd1ca14cea/corejet.core-1.0a1.tar.gz" } ], "1.0a3": [ { "comment_text": "", "digests": { "md5": "76f61e1af7bd4b4fa3676c9aecc1cadb", "sha256": "e7a0dc72ae0b062849c257dba83e8fed84fc6a53c1535630c7ce1b92dfee3c6c" }, "downloads": -1, "filename": "corejet.core-1.0a3.zip", "has_sig": false, "md5_digest": "76f61e1af7bd4b4fa3676c9aecc1cadb", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 22276, "upload_time": "2011-05-20T00:38:43", "url": "https://files.pythonhosted.org/packages/89/7b/b1a27ebea3b1d379b5ab5f160d4ddca9709323ae6c8621c78234eab21cc7/corejet.core-1.0a3.zip" } ], "1.0a4": [ { "comment_text": "", "digests": { "md5": "2c83e90643c65d3951327b9c4e0f7a4e", "sha256": "d6a43490fa38d0ce87305b49ca1d91b824a800265ec407eba96976473074dc33" }, "downloads": -1, "filename": "corejet.core-1.0a4.zip", "has_sig": false, "md5_digest": "2c83e90643c65d3951327b9c4e0f7a4e", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 22361, "upload_time": "2011-05-22T03:15:56", "url": "https://files.pythonhosted.org/packages/ea/66/2418becf841c9cf2b92cd065c3f06417bfd31d5988c2d96f5b3214189771/corejet.core-1.0a4.zip" } ], "1.1.0": [ { "comment_text": "", "digests": { "md5": "76c69debed40700495fbd9e95fc1028a", "sha256": "70c1a92912dcb0fd8b5746748c070173f87ef9bd9b4f65204a53e12f66db44e9" }, "downloads": -1, "filename": "corejet.core-1.1.0.tar.gz", "has_sig": false, "md5_digest": "76c69debed40700495fbd9e95fc1028a", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 23140, "upload_time": "2016-08-26T07:45:03", "url": "https://files.pythonhosted.org/packages/33/12/702eaef0d1a883e2d321ab1c76d6e0d7d344c81f9c06246abc4e8b888080/corejet.core-1.1.0.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "76c69debed40700495fbd9e95fc1028a", "sha256": "70c1a92912dcb0fd8b5746748c070173f87ef9bd9b4f65204a53e12f66db44e9" }, "downloads": -1, "filename": "corejet.core-1.1.0.tar.gz", "has_sig": false, "md5_digest": "76c69debed40700495fbd9e95fc1028a", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 23140, "upload_time": "2016-08-26T07:45:03", "url": "https://files.pythonhosted.org/packages/33/12/702eaef0d1a883e2d321ab1c76d6e0d7d344c81f9c06246abc4e8b888080/corejet.core-1.1.0.tar.gz" } ] }