Metadata-Version: 1.0
Name: ftw.testing
Version: 1.6.1
Summary: Provides some testing helpers and an advanced MockTestCase.
Home-page: https://github.com/4teamwork/ftw.testing
Author: Jonas Baumann
Author-email: mailto:info@4teamwork.ch
License: GPL2
Description: ftw.testing
        ===========
        
        
        This package provides helpers for writing tests.
        
        .. figure:: http://onegov.ch/approved.png/image
           :align: right
           :target: http://onegov.ch/community/zertifizierte-module/ftw.testing
        
           Certified: 01/2013
        
        .. contents:: Table of Contents
        
        
        Browser testing with splinter
        -----------------------------
        
        `Splinter`_ is a library which provides a common browser API with a driver
        for `zope.testbrowser`.
        
        The `ftw.testing` package provides integration of `Splinter`_ with Plone
        using Page Objects.
        
        For using the splinter features, use the `splinter` extras require::
        
            ftw.testing [splinter]
        
        
        Setting a package up for browser tests
        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        
        It's easy to setup your package for browser tests:
        
        - Add a test-dependency to `ftw.testing` in your `setup.py`:
        
        .. code:: python
        
            tests_require = [
                'ftw.testing[splinter]',
                ]
        
            setup(name='my.package',
                  ...
                  tests_require=tests_require,
                  extras_require=dict(tests=tests_require),
                  )
        
        - In your `testing.py` use the `FunctionalSplinterTesting` layer wrapper:
        
        .. code:: python
        
            from ftw.testing import FunctionalSplinterTesting
            from plone.app.testing import PLONE_FIXTURE
            from plone.app.testing import PloneSandboxLayer
            from plone.app.testing import applyProfile
            from zope.configuration import xmlconfig
        
        
            class MyPackageLayer(PloneSandboxLayer):
        
                defaultBases = (PLONE_FIXTURE,)
        
                def setUpZope(self, app, configurationContext):
                    import my.package
                    xmlconfig.file('configure.zcml', my.package)
        
                def setUpPloneSite(self, portal):
                    applyProfile(portal, 'my.package:default')
        
        
            MY_PACKAGE_FIXTURE = MyPackageLayer()
            MY_PACKAGE_FUNCTIONAL_TESTING = FunctionalSplinterTesting(
                bases=(MY_PACKAGE_FIXTURE, ),
                name="my.package:functional")
        
        - Write tests using the Plone Page Objects:
        
        .. code:: python
        
            from ftw.testing import browser
            from ftw.testing.pages import Plone
            from my.package.testing import MY_PACKAGE_FUNCTIONAL_TESTING
            from plone.app.testing import SITE_OWNER_NAME
            from plone.app.testing import SITE_OWNER_PASSWORD
            from unittest2 import TestCase
        
        
            class TestDocument(TestCase):
        
                layer = MY_PACKAGE_FUNCTIONAL_TESTING
        
                def test_add_document(self):
                    Plone().login(SITE_OWNER_NAME, SITE_OWNER_PASSWORD)
                    Plone().visit_portal()
                    Plone().create_object('Page', {'Title': 'Foo',
                                                   'Body Text': '<b>Hello World</b>'})
                    self.assertTrue(browser().is_text_present('Hello World'))
        
        
        Writing Page Objects
        ~~~~~~~~~~~~~~~~~~~~
        
        Write your own Page Objects for your views and content types.
        Put a module `pages.py` in your tests folder:
        
        .. code:: python
        
            from ftw.testing.pages import Plone
        
        
            class MyContentType(Plone):
        
                def create_my_content(self, title, text):
                    self.create_object('MyContent', {'Title': title,
                                                     'Body Text': text})
                    return self
        
        The Page Object should have methods for all features of your view.
        
        
        
        Using the Plone Page Objects
        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        
        The Plone page object provided by `ftw.testing` already has the most
        important features built in, such as:
        
        - portal_url handling
        - Login
        - Accessing Headings, <body>-CSS-classes, status messages
        - Adding content
        - TinyMCE handling
        
        Currently it's best to just look in the
        `page object code <https://github.com/4teamwork/ftw.testing/blob/master/ftw/testing/pages.py>`_.
        
        
        
        MockTestCase
        ------------
        
        ``ftw.testing`` provides an advanced MockTestCase which provides bases on
        the `plone.mocktestcase`_ ``MockTestCase``.
        
        .. code:: python
        
            from ftw.testing import MockTestCase
        
        
        The following additional methods are available:
        
        ``self.providing_mock(interfaces, *args, **kwargs)``
              Creates a mock which provides ``interfaces``.
        
        ``self.mock_interface(interface, provides=None, *args, **kwargs)``
              Creates a mock object implementing ``interface``. The mock does not
              only provide ``interface``, but also use it as specification and
              asserts that the mocked methods do exist on the interface.
        
        ``self.stub(*args, **kwargs)``
              Creates a stub. It acts like a mock but has no assertions.
        
        ``self.providing_stub(interfaces, *args, **kwargs)``
              Creates a stub which provides ``interfaces``.
        
        ``self.stub_interface(interface, provides=None, *args, **kwargs)``
              Does the same as ``mock_interface``, but disables counting of expected
              method calls and attribute access. See "Mocking vs. stubbing" below.
        
        ``self.set_parent(context, parent_context)``
              Stubs the ``context`` so that its acquisition parent is ``parent_context``.
              Expects at least context to be a mock or a stub. Returns the ``context``.
        
        ``self.stub_request(interfaces=[], stub_response=True, content_type='text/html', status=200)``
              Returns a request stub which can be used for rendering templates. With the
              ``stub_response`` option, you can define if the request should stub a
              response by itself. The other optional arguments:
              ``content_type``: Defines the expected output content type of the response.
              ``status``: Defines the expected status code of the response.
        
        ``self.stub_response(request=None, content_type='text/html', status=200))``
              Returns a stub response with some headers and options. When a ``request``
              is given the response is also added to the given request.
              The other optional arguments:
              ``content_type``: Defines the expected output content type of the response.
              ``status``: Defines the expected status code of the response.
        
        ``self.assertRaises(*args, **kwargs)``
              Uses ``unittest2`` implementation of assertRaises instead of
              ``unittest`` implementation.
        
        It also fixes a problem in ``mock_tool``, where the ``getToolByName`` mock
        had assertions which is not very useful in some cases.
        
        
        Mocking vs. stubbing
        --------------------
        
        A **mock** is used for testing the communication between two objects. It
        asserts *method calls*. This is used when a test should not test if
        a object has a specific state after doing something (e.g. it has it's
        attribute *xy* set to something), but if the object *does* something
        with another object. If for example an object `Foo` sends an email
        when method `bar` is called, we could mock the sendmail object and
        assert on the send-email method call.
        
        On the other hand we often have to test the state of an object (attribute
        values) after doing something. This can be done without mocks by just
        calling the method and asserting the attribute values. But then we have
        to set up an integration test and install plone, which takes very long.
        For testing an object with dependencies to other parts of plone in a
        unit test, we can use **stubs** for faking other (separately tested) parts
        of plone. Stubs work like mocks: you can "expect" a method call and
        define a result. The difference between **stubs** and **mocks** is that
        stubs do not assert the expectations, so there will be no errors if
        something expected does not happen. So when using stubs we can assert
        the state without asserting the communcation between objects.
        
        
        Component registry layer
        ------------------------
        
        The ``MockTestCase`` is able to mock components (adapters, utilities). It
        cleans up the component registry after every test.
        
        But when we use a ZCML layer, loading the ZCML of the package it should use
        the same component registry for all tests on the same layer. The
        ``ComponentRegistryLayer`` is a layer superclass for sharing the component
        registry and speeding up tests.
        
        Usage:
        
        .. code:: python
        
            from ftw.testing.layer import ComponentRegistryLayer
        
            class ZCMLLayer(ComponentRegistryLayer):
        
                def setUp(self):
                    super(ZCMLLayer, self).setUp()
        
                    import my.package
                    self.load_zcml_file('configure.zcml', my.package)
        
            ZCML_LAYER = ZCMLLayer()
        
        Be aware that ``ComponentRegistryLayer`` is a base class for creating your
        own layer (by subclassing ``ComponentRegistryLayer``) and is not usable with
        ``defaultBases`` directly. This allows us to use the functions
        ``load_zcml_file`` and ``load_zcml_string``.
        
        
        Mailing test helper
        -------------------
        The Mailing helper object mocks the mailhost and captures sent emails.
        The emails can then be easily used for assertions.
        
        Usage:
        
        .. code:: python
        
            from ftw.testing.mailing import Mailing
            import transaction
        
            class MyTest(TestCase):
                layer = MY_FUNCTIONAL_TESTING
        
             def setUp(self):
                 Mailing(self.layer['portal']).set_up()
                 transaction.commit()
        
             def tearDown(self):
                 Mailing(self.layer['portal']).tear_down()
        
             def test_mail_stuff(self):
                 portal = self.layer['portal']
                 do_send_email()
                 mail = Mailing(portal).pop()
                 self.assertEquals('Subject: ...', mail)
        
        
        Freezing datetime.now()
        -----------------------
        
        When testing code which depends on the current time, it is necessary to set
        the current time to a specific time. The ``freeze`` context manager makes that
        really easy:
        
        .. code:: python
        
            from ftw.testing import freeze
            from datetime import datetime
        
            with freeze(datetime(2014, 5, 7, 12, 30)):
                # test code
        
        The ``freeze`` context manager patches the `datetime` module, the `time` module
        and supports the Zope `DateTime` module. It removes the patches when exiting
        the context manager.
        
        
        Generic Setup uninstall test
        ----------------------------
        
        ``ftw.testing`` provides a test superclass for testing uninstall profiles.
        The test makes a Generic Setup snapshot before installing the package, then
        installs and uninstalls the package, creates another snapshot and diffs it.
        The package is installed without installing its dependencies, because it
        should not include uninstalling dependencies in the uninstall profile.
        
        Appropriate testing layer setup is included and the test runs on a seperate
        layer which should not interfere with other tests.
        
        Simple example:
        
        .. code:: python
        
            from ftw.testing.genericsetup import GenericSetupUninstallMixin
            from ftw.testing.genericsetup import apply_generic_setup_layer
            from unittest2 import TestCase
        
        
            @apply_generic_setup_layer
            class TestGenericSetupUninstall(TestCase, GenericSetupUninstallMixin):
                package = 'my.package'
        
        
        The ``my.package`` is expected to have a Generic Setup profile
        ``profile-my.package:default`` for installing the package and a
        ``profile-my.package:uninstall`` for uninstalling the package.
        It is expected to use ``z3c.autoinclude`` entry points for loading
        its ZCML.
        
        The options are configured as class variables:
        
        **package**
            The dotted name of the package as string, which is used for things such
            as guessing the Generic Setup profile names. This is mandatory.
        
        **is_product** (``False``)
            Set this to True when you have a product, which is when you have
            an ``initialize`` function in your package. This is always the case if you
            define new Archetypes contents.
            The product name is expected to be the same as ``package``.
        
        **autoinclude** (``True``)
            This makes the testing fixture load ZCML using the ``z3c.autoinclude``
            entry points registered for the target ``plone``.
        
        **additional_zcml_packages** (``()``)
            Use this if needed ZCML is not loaded using the ``autoinclude`` option,
            e.g. when you need to load testing zcml. Pass in an iterable of
            dottednames of packages, which contain a ``configure.zcml``.
        
        **additional_products** (``()``)
            A list of additional Zope products to install.
        
        **install_profile_name** (``default``)
            The Generic Setup install profile name postfix.
        
        **uninstall_profile_name** (``uninstall``)
            The Generic Setup uninstall profile name postfix.
        
        **skip_files** (``()``)
            An iterable of Generic Setup files (e.g. ``("viewlets.xml",)``) to be
            ignored in the diff. This is sometimes necessary, because not all
            components can and should be uninstalled properly. For example viewlet
            orders cannot be removed using Generic Setup - but this is not a problem
            they do no longer take effect when the viewlets / viewlet managers are
            no longer registered.
        
        
        Full example:
        
        .. code:: python
        
            from ftw.testing.genericsetup import GenericSetupUninstallMixin
            from ftw.testing.genericsetup import apply_generic_setup_layer
            from unittest2 import TestCase
        
        
            @apply_generic_setup_layer
            class TestGenericSetupUninstall(TestCase, GenericSetupUninstallMixin):
                package = 'my.package'
                is_package = True
                autoinclude = False
                additional_zcml_packages = ('my.package', 'my.package.tests')
                additional_products = ('another.package', )
                install_profile_name = 'default'
                uninstall_profile_name = 'uninstall'
                skip_files = ('viewlets.xml', 'rolemap.xml')
        
        
        Compatibility
        -------------
        
        Runs with `Plone <http://www.plone.org/>`_ `4.1`, `4.2` or `4.3`.
        
        
        Links
        -----
        
        - Main github project repository: https://github.com/4teamwork/ftw.testing
        - Issue tracker: https://github.com/4teamwork/ftw.testing/issues
        - Package on pypi: http://pypi.python.org/pypi/ftw.testing
        - Continuous integration: https://jenkins.4teamwork.ch/search?q=ftw.testing
        
        
        Copyright
        ---------
        
        This package is copyright by `4teamwork <http://www.4teamwork.ch/>`_.
        
        ``ftw.testing`` is licensed under GNU General Public License, version 2.
        
        
        
        
        
        .. _plone.mocktestcase: http://pypi.python.org/pypi/plone.mocktestcase
        .. _Splinter: https://pypi.python.org/pypi/splinter
        
        .. image:: https://cruel-carlota.pagodabox.com/fbb27e21f06d795e60173da59259a1a6
           :alt: githalytics.com
           :target: http://githalytics.com/4teamwork/ftw.testing
        
        Changelog
        =========
        
        
        1.6.1 (2014-04-29)
        ------------------
        
        - Also install profile dependencies before creating a snapshot.
          [deif]
        
        
        1.6.0 (2014-04-29)
        ------------------
        
        - Implement Generic Setup uninstall base test.
          [jone]
        
        
        1.5.2 (2014-02-09)
        ------------------
        
        - Fix ``isinstance`` calls of freezed time in ``freeze`` context manager.
          [jone]
        
        
        1.5.1 (2014-02-08)
        ------------------
        
        - Implement ``freeze`` context manager for freezing the time.
          [jone]
        
        
        1.5.0 (2013-09-24)
        ------------------
        
        - AT form page object: add schemata helper methods for testing visible
          schematas and fields.
          [jone]
        
        
        1.4 (2013-08-26)
        ----------------
        
        - Add custom mailhost class, remembering the sender and recipient
          of each email separately.
          [deif]
        
        - Deprecate @javascript because Selenium with PhantomJS is too unstable.
          Removes tests and documentation, the @javascript decorator still works
          for now but needs to be imported from ftw.testing.browser.
          [jone]
        
        - Page objects: add a Plone.visit(obj) function.
          [jone]
        
        - Fix a rare bug where the MockMailHost message list has been replaced by
          another instance.
          [jone, deif]
        
        
        1.3.1 (2013-05-24)
        ------------------
        
        - Move ``Mailing`` helper class to its own module ``mailing``.
          [deif]
        
        
        1.3 (2013-05-03)
        ----------------
        
        - Drop official Plone 4.0 support.
          [jone]
        
        - Component registry layer: use isolated ZCML layers.
          When using the same layer instances it may conflict with integration or
          functional testing layers.
          [jone]
        
        - Add splinter integration and Plone page objects.
          [jone]
        
        - onegov.ch approved: add badge to readme.
          [jone]
        
        - MockTestCase: Support Products.PloneHotfix20121106 patch when mocking getToolByName.
          [jone]
        
        - MockTestCase: add checks that setUp is called correctly.
          [jone]
        
        
        1.2 (2012-05-22)
        ----------------
        
        - Add ``stub_reponse`` method to ``MockTestCase`` and adjust the
          ``stub_request`` method accordant.
          [phgross]
        
        - Made providing interfaces configurable for the ``stub_request`` method.
          [phgross]
        
        - Let the stub_request method also stub the getStatus of the response.
          [phgross]
        
        - Add ``stub_request`` method to ``MockTestCase``.
          [jone]
        
        - No longer tear down the component registry in mock test case. Use the
          ComponentRegistryLayer.
          [jone]
        
        - Add ``ComponentRegistryLayer`` base class.
          [jone]
        
        - Add ``mock_interface`` and ``stub_interface`` methods to MockTestCase, creating
          a mock and using the interface as spec.
          [jone]
        
        - Accept also interfaces directly rather than lists of interfaces when
          creating mocks or stubs which provides the interfaces.
          [jone]
        
        
        1.1 (2011-11-16)
        ----------------
        
        - Patch mock_tool: do not count, so that it can be used multiple times.
          [jone]
        
        
        1.0 (2011-10-12)
        ----------------
        
        - Initial release
        
Keywords: ftw testing mocking testcase mock stub
Platform: UNKNOWN
Classifier: Framework :: Plone
Classifier: Framework :: Plone :: 4.1
Classifier: Framework :: Plone :: 4.2
Classifier: Framework :: Plone :: 4.3
Classifier: Programming Language :: Python
Classifier: Topic :: Software Development :: Libraries :: Python Modules
