[Zope3-dev] Mail delivery failed: returning message to sender
Mail Delivery System
Mailer-Daemon at python.org
Tue Feb 17 07:56:05 EST 2004
This message was created automatically by mail delivery software.
A message that you sent could not be delivered to one or more of its
recipients. This is a permanent error. The following address(es) failed:
corey at streamreel.net
SMTP error from remote mailer after RCPT TO:<corey at streamreel.net>:
host iris2.directnic.com [204.251.10.82]: 550 5.7.1 No such recipient
------ This is a copy of the message, including all the headers. ------
Return-path: <zope3-dev at zope.org>
Received: from cache1.zope.org ([12.155.117.38])
by mail.python.org with esmtp (Exim 4.22)
id 1At4iI-0007VT-Kx; Tue, 17 Feb 2004 07:52:34 -0500
From: zope3-dev at zope.org (srichter)
Reply-To: zope3-dev at zope.org
To: ;
Subject: [FunctionalTests] (new) first draft (generated from LaTeX file)
Message-ID: <20040217075234EST at dev.zope.org>
X-BeenThere: zope3-dev at zope.org
X-Zwiki-Version: 0.21.1
Precedence: bulk
List-Id: <zope3-dev at zope.org>
List-Post: <mailto:zope3-dev at zope.org>
List-Subscribe: <http://dev.zope.org/Wikis/DevSite/Projects/ComponentArchitecture/FunctionalTests/subscribeform>
List-Unsubscribe: <http://dev.zope.org/Wikis/DevSite/Projects/ComponentArchitecture/FunctionalTests/subscribeform>
List-Archive: <http://dev.zope.org/Wikis/DevSite/Projects/ComponentArchitecture/FunctionalTests>
List-Help: <http://dev.zope.org/Wikis/DevSite/Projects/ComponentArchitecture>
Date: Tue, 17 Feb 2004 07:52:34 -0500
X-Spam-Status: OK (default 0.000)
Writing Functional Tests
Status
IsDraft
Authors
StephanRichter
Difficulty
Newcomer Level
Skills
- It would be nice to knwo how Zope 3 generated forms work.
Optional.
Problem/Task
Unit tests cover a large part of the testing requirements listed in
the eXtreme Programming literature, but are not everything. There are
also regression and functional tests. While regression tests can be
handled with unit and doc tests, functional tests can't. For this reason
the Zope 3 community members developed an extension to 'unittest'
that handle functional tests. This package is introduced in this recipe.
Recipe
Introduction
Unit tests are very good for testing the functionality of a
particular object in absence of the environment it will eventually live
in. Regression tests build on this by testing the behavior of an object
in a limited environment. Then functional tests should test the behavior
of an object in a fully running system. Therefore functional tests often
check the user interface behavior and it is not surprising that they are
often found in the browser code of Zope. In fact, in Zope 3's
implementation of functional tests there exists a base test case class
for each view type, such as 'zope.testing.functional.BrowserTestCase'
or 'zope.app.dav.ftests.dav.DAVTestCase' .
Each custom functional test case class provides some valuable
methods that help you write the tests fast and efficiently. Here are the
methods that the 'BrowserTestCase' provides.
-'getRootFolder()'
Returns the root folder of the database. This method is available in
every functional test case class.
-'makeRequest(path='', basic=None, form=None, env='
This class creates a new 'BrowserRequest' instance that can be used
for publishing.
-'path' - This is the absolute path of the URL (i.e. the URL
minus the protocol, server and port).
-'basic' - It provides the authentication information of the
format '"<login>:<password>"' . When Zope 3 is brought up
for functional testing, a user with the login "mgr" and the password
"mgrpw" is automatically created having the role "zope.Manager"
assigned to it. So usually you will use '"mgr:mgrpw"' as
your basic argument.
-'form' - The argument is a dictionary that contains all
fields that would be provided by an HTML form. Note that you should
have covnerted the data already to their native Python format; be
sure to only use unicode for strings.
-'env' - This variable is also a dicationary where you can
specify further environment variables, like HTTP headers. For
example, the header 'X-Header: value' would be an entry of
the form ''HTTP' in the dictionary.
-'outstream' - Optionally you can define the the stream to
which the outputted HTML is sent. If you do not specify one, one will
be created for you.
However, one would often not use this method directly, since it
does not actually publish the request. Use the 'publish()'
method described below.
-'publish(self, path, basic=None, form=None, env='
The method creates a request, that is then published in a completely
functional Zope 3 and finally returns a regular response object that is
enhanced by a couple of methods:
-'getOutput()' - Returns all of the text that was pushed to
the outstream.
-'getBody()' - Only returns all of the HTML of the response.
It therefore excludes HTTP headers.
-'getPath()' - Returns the path that was passed to the
request.
The 'path' , 'basic' , 'form' and 'env' have the same semantics
as the equally-named arguments to 'makeRequest()' . If 'handle'
is 'False' , then occuring exceptions are not caught. If 'True'
, the default view of an exception is used and a nice formatted HTML
page will be returned.
-'checkForBrokenLinks(body, path, basic=None)'
Given an output body and a published path, check whether the contained
HTML contains any links and check that these links work. Since the
availability of pages and therefore links depends on the permissions of
the user, one might want to specify a login/password pair in basic. For
example, if you have published a request as a manager, it will be very
likely that the returned HTML contains links that require the manager
role.
Testing "Templated Page" Views
Okay, now that we know how the 'BrowserTestCase' extends the normal
'unittest.TestCase' , we can use it to write some functional tests
for the "add", "edit" and "index" view of the "Templated Page" content
type.
Anywhere, create a file called 'test' and add the following
functional testing code::
01 import time
02 import unittest
04 from transaction import get_transaction
05 from zope.testing.functional import BrowserTestCase
06 from zope.app.content.zpt import ZPTPage
08 class TemplatedPageTests(BrowserTestCase):
09 """Funcional tests for Templated Page."""
11 template = u'''
12 <html>
13 <body>
14 <h1 tal:content="modules/time/asctime" />
15 </body>
16 </html>'''
18 template2 = u'''
19 <html>
20 <body>
21 <h1 tal:content="modules/time/asctime">time</h1>
22 </body>
23 </html>'''
25 def createPage(self):
26 root = self.getRootFolder()
27 root['zptpage'] = ZPTPage()
28 root['zptpage'].setSource(self.template, 'text/html')
29 get_transaction().commit()
31 def test_add(self):
32 response = self.publish(
33 "/+/zope.app.content.zpt.ZPTPage=",
34 basic='mgr:mgrpw',
35 form={'add_input_name' : u'newzptpage',
36 'field.expand.used' : u'',
37 'field.source' : self.template,
38 'field.evaluateInlineCode.used' : u'',
39 'field.evaluateInlineCode' : u'on',
40 'UPDATE_SUBMIT' : 'Add'})
42 self.assertEqual(response.getStatus(), 302)
43 self.assertEqual(response.getHeader('Location'),
44 'http://localhost/@@contents.html')
46 zpt = self.getRootFolder()['newzptpage']
47 self.assertEqual(zpt.getSource(), self.template)
48 self.assertEqual(zpt.evaluateInlineCode, True)
50 def test_editCode(self):
51 self.createPage()
52 response = self.publish(
53 "/zptpage/@@edit.html",
54 basic='mgr:mgrpw',
55 form={'add_input_name' : u'zptpage',
56 'field.expand.used' : u'',
57 'field.source' : self.template2,
58 'UPDATE_SUBMIT' : 'Change'})
59 self.assertEqual(response.getStatus(), 200)
60 self.assert_(response.getBody().find('asctime">time</h1>') != -1)
61 self.checkForBrokenLinks(response.getBody(), response.getPath(),
62 'mgr:mgrpw')
64 def test_index(self):
65 self.createPage()
66 t = time.asctime()
67 response = self.publish("/zptpage", basic='mgr:mgrpw')
68 self.assertEqual(response.getStatus(), 200)
69 self.assert_(response.getBody().find(self.template2) != -1)
70 self.checkForBrokenLinks(response.getBody(), response.getPath(),
71 'mgr:mgrpw')
73 def test_suite():
74 return unittest.TestSuite((
75 unittest.makeSuite(TemplatedPageTests),
76 ))
78 if __name__=='__main__':
79 unittest.main(defaultTest='test_suite')
o Line 25-29: This is the perfect example of a helper method. It
creates a "Templated Page" content object called 'zptpage' . To
write the new object to the ZODB, you have to commit the transaction
using 'get' .
o Line 31-48: To understand this test completely, it is surely
helpful to be familiar with the way Zope 3 adds new objects and how the
widgets create an HTML form. The "+"-sign in the URL is the adding view
for a folder. The path that follows is simply the factory id of the
content type (line 33).
The form dictionary is another piece of information that must be
carefully constructed. First of all, the 'field.expand.used' and
'field.evaluateInlineCode.used' are required, whether you want
to activate 'expand' and 'evaluateInlineCode' or not. It is
required by the corresponding widgets. The 'add' key maps to the
name the content object will recieve and 'UPDATE' just tells the
form generator that the form was actually submitted and action should
be taken. To make it easier on myself, I just created a "Templated
Page" on the browser parallel to writing the functional test to get all
of the above information.
On line 42, we check whether the request was successful. Code
302 signalizes a redirect and on line 43 we check that we are
redirected to the correct page.
Now, it is time to check in the ZODB whether the object has
really been created and that all data was set correctly. On line 46 we
retrieve the object itself and consequently we check that the source is
set correctly and the 'evaluateInlineCode' flag was turned as
request in the form (line 39).
o Line 50-62: Before we can test whether the data of a "Templated
Page" can be edited correctly, we have to create one. Here the 'createPage()'
method comes in handy, which quickly creates a page that we can use.
Having done previous test already, the contents of the 'form'
dictionary should be obvious.
Since the edit page returns itself, the status of the response
should be 200. We also inspect the body of the response to make sure
that the temlpate was stored correctly.
One extremly useful feautre of the 'BrowserTestCase' is the
check for broken links in the returned page. I would suggest that you
do this test whenever a HTML page is returned by the response.
o Line 64-71: Here we simply test the default view of the
"Templated Page". No complicated forms or environments are needed. We
just need to make sure that the template is executed correctly.
Running Functional Tests
The testing code directly depends on the Zope 3 source tree, so make
sure to have it in you Python path. In Un*x/Linux you can do this using::
export PYTHONPATH=$PYTHONPATH:<ZOPE3>/src
where '<ZOPE3>' is the path to you Zope 3 installation.
Furthermore, functional tests depend on finding a file called 'ftesting.zcml'
, which is used to bring up the Zope 3 application server. Therefore it
is best to just go to the directory '<ZOPE3>' , since there exists
such a file. You can now execute our new funtional tests using::
python path/to/ftest/test_templatedpage.py
You will notice that these tests will take a couple seconds (5-10 seconds)
to run. This is okay, since the functional tests have to bring up the
entire Zope 3 system, which by itself will take about 4 seconds.
Exercises
- Exercise 1: Add another functional test that checks the
"Preview" and "Inline Code" screen.
--
forwarded from http://dev.zope.org/Wikis/DevSite/Projects/ComponentArchitecture/FunctionalTests
More information about the Zope3-dev
mailing list