Welcome, guest | Sign In | My Account | Store | Cart

Notice! PyPM is being replaced with the ActiveState Platform, which enhances PyPM’s build and deploy capabilities. Create your free Platform account to download ActivePython or customize Python with the packages you require and get automatic updates.

Download
ActivePython
INSTALL>
pypm install ftw.builder

How to install ftw.builder

  1. Download and install ActivePython
  2. Open Command Prompt
  3. Type pypm install ftw.builder
 Python 2.7Python 3.2Python 3.3
Windows (32-bit)
Windows (64-bit)
Mac OS X (10.5+)
Linux (32-bit)
Linux (64-bit)
1.0.0 Available View build log
 
License
GPL2
Lastest release
version 1.0.0 on Jan 9th, 2014

ftw.builder

Create Plone objects in tests with the Builder Pattern.

The builder pattern simplifies constructing objects. In tests we often need to create Plone objects, sometimes a single object, sometimes a whole graph of objects. Using the builder pattern allows us to do this in a DRY way, so that we do not repeat this over and over.

System Message: ERROR/3 (<string>, line 13)

Unknown directive type "code".

.. code:: python

    from ftw.builder import create
    from ftw.builder import Builder

    def test_foo(self):
        folder = create(Builder('folder')
                        .titled('My Folder')
                        .in_state('published'))


Installation

Add ftw.builder as (test-) dependency to your package in setup.py:

System Message: ERROR/3 (<string>, line 29)

Unknown directive type "code".

.. code:: python

    tests_require = [
        'ftw.builder',
        ]

    setup(name='my.package',
          tests_require=tests_require,
          extras_require={'tests': tests_require})


Usage

Setup builder session in your testcase

System Message: ERROR/3 (<string>, line 45)

Unknown directive type "code".

.. code:: python

    class TestPerson(unittest2.TestCase):

        def setUp(self):
            session.current_session = session.factory()

        def tearDown(self):
            session.current_session = None

In plone projects you can use the BUILDER_LAYER which your testing layer should base on. So the the session management is handled by the BUILDER_LAYER:

System Message: ERROR/3 (<string>, line 57)

Unknown directive type "code".

.. code:: python

    from ftw.builder.testing import BUILDER_LAYER

    class MyPackageLayer(PloneSandboxLayer):

        defaultBases = (PLONE_FIXTURE, BUILDER_LAYER)

Use the builder for creating objects in your tests:

System Message: ERROR/3 (<string>, line 67)

Unknown directive type "code".

.. code:: python


    from ftw.builder import Builder
    from ftw.builder import create
    from my.package.testing import MY_PACKAGE_INTEGRATION_TESTING
    from unittest2 import TestCase

    class TestMyFeature(TestCase)

        layer = MY_PACKAGE_INTEGRATION_TESTING

        def test_folder_is_well_titled(self):
            folder = create(Builder('folder')
                            .titled('My Folder')
                            .in_state('published'))

            self.assertEquals('My Folder', folder.Title())


Session

The BuilderSession keeps configuration for multiple builders. It is set up and destroyed by the BUILDER_LAYER and can be configured or replaced by a custom session with set_builder_session_factory.

Auto commit

When having a functional testing layer (plone.app.testing.FunctionalTesting) and doing browser tests it is necessary that the new objects are committed in the ZODB. When using a IntegrationTesting on the other hand it is essential that nothing is comitted, since this would break test isolation.

The session provides the auto_commit option (dislabed by default), which commits to the ZODB after creating an object. Since it is disabled by default you need to enable it in functional test cases.

A default session factory functional_session_factory that enables the auto-commit feature is provided:

System Message: ERROR/3 (<string>, line 109)

Unknown directive type "code".

.. code:: python

    def functional_session_factory():
        sess = BuilderSession()
        sess.auto_commit = True
        return sess


You can use set_builder_session_factory to replace the default session factory in functional tests. Make sure to also base your fixture on the BUILDER_LAYER fixture:

System Message: ERROR/3 (<string>, line 121)

Unknown directive type "code".

.. code:: python

    from ftw.builder.session import BuilderSession
    from ftw.builder.testing import BUILDER_LAYER
    from ftw.builder.testing import functional_session_factory
    from ftw.builder.testing import set_builder_session_factory
    from plone.app.testing import FunctionalTesting
    from plone.app.testing import IntegrationTesting
    from plone.app.testing import PLONE_FIXTURE
    from plone.app.testing import PloneSandboxLayer


    class MyPackageLayer(PloneSandboxLayer):
        defaultBases = (PLONE_FIXTURE, BUILDER_LAYER)

    MY_PACKAGE_FIXTURE = MyPackageLayer()

    MY_PACKAGE_INTEGRATION_TESTING = IntegrationTesting(
        bases=(MY_PACKAGE_FIXTURE, ),
        name="MyPackage:Integration")

    MY_PACKAGE_FUNCTIONAL_TESTING = FunctionalTesting(
        bases=(MY_PACKAGE_FIXTURE,
               set_builder_session_factory(functional_session_factory)),
        name="MyPackage:Integration")





Plone object builders

For creating Plone objects (Archetypes or Dexterity) there are some methods for setting basic options:

  • within(container) - tell the builder where to create the object
  • titled(title) - name the object
  • having(field=value) - set the value of any field on the object
  • in_state(review_state) - set the object into any review state of the workflow configured for this type
Default builders

The ftw.builder ships with some builders for some default Plone (Archetypes) content types, but the idea is that you can easily craft your own builders for your types or extend existing builders.

The built-in builders are:

  • folder - creates an Archetypes folder
  • page (or Document) - creates an Archetypes page (alias Document)
  • file - creates a File
Attaching files

The default Archetypes file builder let's you attach a file or create the file with dummy content:

System Message: ERROR/3 (<string>, line 184)

Unknown directive type "code".

.. code:: python

    file1 = create(Builder('file')
                   .with_dummy_content())

    file2 = create(Builder('file')
                   .attach_file_containing('File content', name='filename.pdf')


Creating new builders

The idea is that you create your own builders for your application. This might be builders creating a single Plone object (Archetypes or Dexterity) or builders creating a set of objects using other builders.

Creating python builders

Define a simpe builder class for your python object and register them in the builder registry

System Message: ERROR/3 (<string>, line 205)

Unknown directive type "code".

.. code:: python

    class PersonBuilder(object):

        def __init__(self, session):
            self.session = session
            self.children_names = []
            self.arguments = {}

        def of_age(self):
            self.arguments['age'] = 18
            return self

        def with_children(self, children_names):
            self.children_names = children_names
            return self

        def having(self, **kwargs):
            self.arguments.update(kwargs)
            return self

        def create(self, **kwargs):
            person = Person(
                self.arguments.get('name'),
                self.arguments.get('age'))

            for name in self.children_names:
                person.add_child(
                    create(Builder('person').having(name=name, age=5))
                )

            return person

    builder_registry.register('person', PersonBuilder)


Creating Archetypes builders

Use the ArchetypesBuilder base class for creating new Archetypes builders. Set the portal_type and your own methods.

System Message: ERROR/3 (<string>, line 247)

Unknown directive type "code".

.. code:: python

    from ftw.builder.archetypes import ArchetypesBuilder
    from ftw.builder import builder_registry

    class NewsBuilder(ArchetypesBuilder):
        portal_type = 'News Item'

        def containing(self, text):
            self.arguments['text'] = text
            return self

    builder_registry.register('news', NewsBuilder)


Creating Dexterity builders

Use the DexterityBuilder base class for creating new Dexterity builders. Set the portal_type and your own methods.

System Message: ERROR/3 (<string>, line 268)

Unknown directive type "code".

.. code:: python

    from ftw.builder.dexterity import DexterityBuilder
    from ftw.builder import builder_registry

    class DocumentBuilder(DexterityBuilder):
        portal_type = 'dexterity.document'

        def with_dummy_content(self):
            self.arguments["file"] = NamedBlobFile(data='Test data', filename='test.doc')
            return self


Events

You can do things before and after creating the object:

System Message: ERROR/3 (<string>, line 286)

Unknown directive type "code".

.. code:: python

    class MyBuilder(ArchetypesBuilder):

        def before_create(self):
            super(NewsBuilder, self).before_create()
            do_something()

        def after_create(self):
            do_something()
            super(NewsBuilder, self).after_create()


Overriding existing builders

Sometimes it is necessary to override an existing builder. For re-registering an existing builder you can use the force flag:

System Message: ERROR/3 (<string>, line 306)

Unknown directive type "code".

.. code:: python

    builder_registry.register('file', CustomFileBuilder, force=True)


Development / Tests

System Message: ERROR/3 (<string>, line 314)

Unknown directive type "code".

.. code:: bash

    $ git clone https://github.com/4teamwork/ftw.builder.git
    $ cd ftw.builder
    $ ln -s development.cfg buildout.cfg
    $ python2.7 bootstrap.py
    $ ./bin/buildout
    $ ./bin/test



Changelog

1.0.0 (2013-08-12)
  • Added dexterity support. [phgross]
  • Initial implementation [jone]

Subscribe to package updates

Last updated Jan 9th, 2014

What does the lock icon mean?

Builds marked with a lock icon are only available via PyPM to users with a current ActivePython Business Edition subscription.

Need custom builds or support?

ActivePython Enterprise Edition guarantees priority access to technical support, indemnification, expert consulting and quality-assured language builds.

Plan on re-distributing ActivePython?

Get re-distribution rights and eliminate legal risks with ActivePython OEM Edition.