py.test examples for Grok
=========================

In typical Zope/Grok development we have three kinds of tests:

  - unit-tests
  - integration-tests
  - funktional-tests

With the help of py.test we can create and run all of these tests in
an easy way for Grok. In this tutorial we will demonstrate the usage
of zope.pytest with this three kinds of tests.


Buildout
--------

Let's start by extending the default ``buildout.cfg`` generated by
`grokproject` to use zope.pytest.

To find all relevant packages of pytest we have to add 

    http://pypi.testrun.org/simple/py/

to the find_links.

Then we can add a new section called ``pytest``. Don't forget to add it 
to the global parts too!

Here is the pytest section::

    [pytest]
    recipe = z3c.recipe.scripts
    eggs =
      example 
      pytest
    arguments = ['src/example'] + sys.argv[1:]

Please notice that ``example`` is the name of the package generated by
`grokproject`.

After running ``bin/buildout`` we should have a new executable called
``bin/py.test`` which can search for tests in the directory
``src/example``.


Unit Tests
----------

To run unit tests with `pytest` we have to create a file with the
prefix ``test_``. So, let's create a file ``test_unit.py`` with the
following content:

.. code-block:: python

    class TestClass:

        def test_one(self):
            x = "this"
            assert 'h' in x

        def test_two(self):
            x = "servus"
            assert x == "hello"


Now we can run this test with ``bin/py.test``. We should get one
failing test::


    ==================================== FAILURES =====================================
    _______________________________ TestClass.test_two ________________________________

    self = <pytt.tests.test_unit.TestClass instance at 0x1042d0950>

        def test_two(self):
            x = "servus"
    >       assert x == "hello"
    E       assert 'servus' == 'hello'
    E         - servus
    E         + hello

    src/pytt/tests/test_unit.py:9: AssertionError
    ======================= 1 failed, 3 passed in 1.14 seconds ========================


Integration Tests
-----------------

For integration tests we need a bit more setup. To be more precise we
have to load the Zope Component Architecture before respective tests
are actually run.

To run the integration test we need a bit of code that registers
something in the Zope Component Architecture. Take a look at this
example in ``app.py``:

.. code-block:: python 

    import grok

    class Example(grok.Application, grok.Container):
        pass

    class Index(grok.View):
    
        def render(self):
            return "Hello World"

Now we have some code to test.

We have to create another module which contains our test and whose
name is prefixed with ``test_``.  This time we name it
``test_integration.py``:

.. code-block:: python

    import example 
    import pytest

    from zope import component
    from example.app import Example
    from zope.publisher.browser import TestRequest
    from zope.pytest import create_app, configure


    def pytest_funcarg__app(request):
        return create_app(request, Example())

    def pytest_funcarg__config(request):
        return configure(request, pytt, 'ftesting.zcml')


    def test_integration(app, config):
        zope_req = TestRequest()
        view = component.getMultiAdapter(
            (Example(), zope_req), name=u"index")
        assert "Hello World" in view()

The interesting bits are the two ``pytest_funcarg__`` functions: 

  - ``pytest_funcarg__app``
        This function creates a test ZODB with our `Example`
        application in the ZODB root.

  - ``pytest_funcarg__config``
        This function sets up the Zope Component Registry which groks
        in this case the contents of our app.py.

Now you can run ``bin/py.test`` again and will see that pytest will
discover and execute this ``test_integration`` module.


Functional Tests
----------------

We take again the example in the app.py file for demonstrating
the functional tests with zope.pytest in grok. Functional tests
showing the perspective of a user. This means we test here
with a kind of a browser. We take for this infrae.testbrowser.

We have to include it in our setup.py install_requires.

Again we creat a module called test_functional.py.

.. code-block:: python 

    import example 
    import pytest

    from example.app import Example
    from zope.pytest import create_app, configure

    from infrae.testbrowser.browser import Browser

    def pytest_funcarg__app(request):
        return create_app(request, Example())

    def pytest_funcarg__config(request):
        return configure(request, pytt, 'ftesting.zcml')

    def test_with_infrae_testbrowser(config, app):
        browser = Browser(app)
        browser.options.handle_errors = False
        browser.open('http://localhost/test')
        assert browser.status == '200 Ok'

We use again the pytest_funcarg functions to setup a ZODB
and the Zope Component Architecture. In our test function
we create an instance of Browser with our app as argument.

Now we can open our Index site in the browser and check
for example the HTTP Response Status.

You can run now again bin/py.test and look on the running test.
