Part 3: Testing Dexterity¶
Create simple Dexterity Type¶
Add Dexterity to the package (setup.py):
install_requires=[
'plone.api',
'setuptools',
'z3c.jbot',
'plone.app.dexterity',
'plone.app.portlets',
Make sure dexterity is installed together with the package:
<?xml version="1.0"?>
<metadata>
<version>1000</version>
<dependencies>
<dependency>profile-plone.app.dexterity:default</dependency>
</dependencies>
</metadata>
configure.zcml:
<includeDependencies package="." />
Create profiles/default/types directory:
$ mkdir profiles/default/types
Create Factory Type Information (FTI) for Task Type (profiles/default/types/Task.xml):
<?xml version="1.0"?>
<object name="Task" meta_type="Dexterity FTI" i18n:domain="plonetraining.testing"
xmlns:i18n="http://xml.zope.org/namespaces/i18n">
<property name="title" i18n:translate="">Task</property>
<property name="description"
i18n:translate=""></property>
<property name="icon_expr">string:${portal_url}/++theme++plonetraining.testing/Task.png</property>
<property name="factory">Task</property>
<property name="add_view_expr">string:${folder_url}/++add++Task</property>
<property name="link_target"></property>
<property name="immediate_view">view</property>
<property name="global_allow">True</property>
<property name="filter_content_types">True</property>
<property name="allowed_content_types">
</property>
<property name="allow_discussion">False</property>
<property name="default_view">view</property>
<property name="view_methods">
<element value="view"/>
</property>
<property name="default_view_fallback">False</property>
<property name="add_permission">cmf.AddPortalContent</property>
<property name="klass">plone.dexterity.content.Item</property>
<property name="behaviors">
<element value="plone.app.content.interfaces.INameFromTitle"/>
</property>
<property name="schema">plonetraining.testing.interfaces.ITask</property>
<property name="model_source"></property>
<property name="model_file"></property>
<alias from="(Default)" to="(dynamic view)"/>
<alias from="edit" to="@@edit"/>
<alias from="sharing" to="@@sharing"/>
<alias from="view" to="(selected layout)"/>
<action title="View" action_id="view" category="object" condition_expr=""
description="" icon_expr="" link_target="" url_expr="string:${object_url}"
visible="True">
<permission value="View"/>
</action>
<action title="Edit" action_id="edit" category="object" condition_expr=""
description="" icon_expr="" link_target=""
url_expr="string:${object_url}/edit" visible="True">
<permission value="Modify portal content"/>
</action>
</object>
Include Task FTI in Generic Setup Profile (profiles/default/types.xml):
<?xml version="1.0"?>
<object name="portal_types" meta_type="Plone Types Tool">
<object name="Task" meta_type="Dexterity FTI"/>
</object>
Interface¶
interfaces.py:
# -*- coding: utf-8 -*-
from plonetraining.testing import _
from zope import schema
from zope.interface import Interface
from zope.publisher.interfaces.browser import IDefaultBrowserLayer
class IPlonetrainingTestingLayer(IDefaultBrowserLayer):
"""Marker interface that defines a browser layer."""
class ITask(Interface):
title = schema.TextLine(
title=_(u"Title"),
required=True,
)
description = schema.Text(
title=_(u"Description"),
required=False,
)
Integration Test¶
tests/test_task.py:
# -*- coding: utf-8 -*-
from plone.app.testing import SITE_OWNER_NAME
from plone.app.testing import SITE_OWNER_PASSWORD
from plone.testing.z2 import Browser
from plone.app.testing import TEST_USER_ID
from zope.component import queryUtility
from zope.component import createObject
from plone.app.testing import setRoles
from plone.dexterity.interfaces import IDexterityFTI
from plonetraining.testing.testing import PLONETRAINING_TESTING_FUNCTIONAL_TESTING # noqa
from plonetraining.testing.testing import PLONETRAINING_TESTING_INTEGRATION_TESTING # noqa
from plonetraining.testing.interfaces import ITask
import unittest2 as unittest
class TaskIntegrationTest(unittest.TestCase):
layer = PLONETRAINING_TESTING_INTEGRATION_TESTING
def setUp(self):
self.portal = self.layer['portal']
setRoles(self.portal, TEST_USER_ID, ['Manager'])
def test_schema(self):
fti = queryUtility(IDexterityFTI, name='Task')
schema = fti.lookupSchema()
self.assertEqual(ITask, schema)
def test_fti(self):
fti = queryUtility(IDexterityFTI, name='Task')
self.assertTrue(fti)
def test_factory(self):
fti = queryUtility(IDexterityFTI, name='Task')
factory = fti.factory
task = createObject(factory)
self.assertTrue(ITask.providedBy(task))
def test_adding(self):
self.portal.invokeFactory('Task', 'task')
self.assertTrue(ITask.providedBy(self.portal.task))
Functional Test¶
tests/test_task.py:
# -*- coding: utf-8 -*-
from plone.app.testing import SITE_OWNER_NAME
from plone.app.testing import SITE_OWNER_PASSWORD
from plone.testing.z2 import Browser
from plone.app.testing import TEST_USER_ID
from zope.component import queryUtility
from zope.component import createObject
from plone.app.testing import setRoles
from plone.dexterity.interfaces import IDexterityFTI
from plonetraining.testing.testing import PLONETRAINING_TESTING_FUNCTIONAL_TESTING # noqa
from plonetraining.testing.testing import PLONETRAINING_TESTING_INTEGRATION_TESTING # noqa
from plonetraining.testing.interfaces import ITask
import unittest2 as unittest
class TaskFunctionalTest(unittest.TestCase):
layer = PLONETRAINING_TESTING_FUNCTIONAL_TESTING
def setUp(self):
app = self.layer['app']
self.portal = self.layer['portal']
self.request = self.layer['request']
self.portal_url = self.portal.absolute_url()
# Set up browser
self.browser = Browser(app)
self.browser.handleErrors = False
self.browser.addHeader(
'Authorization',
'Basic %s:%s' % (SITE_OWNER_NAME, SITE_OWNER_PASSWORD,)
)
def test_add_task(self):
self.browser.open(self.portal_url + '/++add++Task')
self.browser.getControl(name="form.widgets.title").value = \
"My Task"
self.browser.getControl(name="form.widgets.description")\
.value = "This is my task"
self.browser.getControl("Save").click()
self.assertEqual(
"My Task",
self.portal['my-task'].title,
)
def test_view_task(self):
setRoles(self.portal, TEST_USER_ID, ['Manager'])
self.portal.invokeFactory(
"Task",
id="my-task",
title="My Task",
)
import transaction
transaction.commit()
self.browser.open(self.portal_url + '/my-task')
self.assertTrue('My Task' in self.browser.contents)
Robot Test¶
tests/robot/test_task.robot:
# ============================================================================
# EXAMPLE ROBOT TESTS
# ============================================================================
#
# Run this robot test stand-alone:
#
# $ bin/test -s plonetraining.testing -t test_task.robot --all
#
# Run this robot test with robot server (which is faster):
#
# 1) Start robot server:
#
# $ bin/robot-server --reload-path src plonetraining.testing.testing.PLONETRAINING_TESTING_ACCEPTANCE_TESTING
#
# 2) Run robot tests:
#
# $ bin/robot src/plonetraining/testing/tests/robot/test_task.robot
#
# See the http://docs.plone.org for further details (search for robot
# framework).
#
# ============================================================================
*** Settings *****************************************************************
Resource plone/app/robotframework/selenium.robot
Resource plone/app/robotframework/keywords.robot
Library Remote ${PLONE_URL}/RobotRemote
Test Setup Open test browser
Test Teardown Close all browsers
*** Test Cases ***************************************************************
Scenario: As a site administrator I can add a Task
Given a logged-in site administrator
and an add task form
When I type 'My Task' into the title field
and I submit the form
Then a task with the title 'My Task' has been created
Scenario: As a site administrator I can view a Task
Given a logged-in site administrator
and a task 'My Task'
When I go to the task view
Then I can see the task title 'My Task'
*** Keywords *****************************************************************
# --- Given ------------------------------------------------------------------
a logged-in site administrator
Enable autologin as Site Administrator
an add task form
Go To ${PLONE_URL}/++add++Task
a task 'My Task'
Create content type=Task id=my-task title=My Task
# --- WHEN -------------------------------------------------------------------
I type '${title}' into the title field
Input Text name=form.widgets.title ${title}
I submit the form
Click Button Save
I go to the task view
Go To ${PLONE_URL}/my-task
Wait until page contains Site Map
# --- THEN -------------------------------------------------------------------
a task with the title '${title}' has been created
Wait until page contains Site Map
Page should contain ${title}
Page should contain Item created
I can see the task title '${title}'
Wait until page contains Site Map
Page should contain ${title}