[Testbot] FAILED (failures=2) : AT-1.5 Plone[next]-3.3 Zope-2.10 Python-2.4.6

Archetypes Tests plone-tests at epy.co.at
Wed Feb 10 02:34:21 UTC 2010


Archetypes Tests : FAILED (failures=2)
AT-1.5 Plone[next]-3.3 Zope-2.10 Python-2.4.6

Running ./bin/instance test -q --package Products.Archetypes --package Products.MimetypesRegistry --package Products.PortalTransforms --package Products.validation
/home/stefan/autotest/temp/cache/Zope-2.10.11-final-py2.4/lib/python/zope/configuration/xmlconfig.py:323: DeprecationWarning: zope.app.annotation has moved to zope.annotation. Import of zope.app.annotation will become unsupported in Zope 3.5
  __import__(arguments[0])
Failed to import ZPsycopgDA
Failed to import ZMySQLDA
Running unit tests:
  Ran 17 tests with 0 failures and 0 errors in 0.205 seconds.
Running Products.PloneTestCase.layer.ZCML tests:
  Set up Products.PloneTestCase.layer.ZCML in 1.509 seconds.
/home/stefan/autotest/temp/python24-zope210-cmf21-plone33next/eggs/Products.PlonePAS-3.12-py2.4.egg/Products/PlonePAS/setuphandlers.py:39: DeprecationWarning: portal_groups.getGroupIds is deprecated and will be removed in Plone 4.0. Use PAS searchGroups instead
  existing = gtool.listGroupIds()
  Ran 61 tests with 0 failures and 0 errors in 0.942 seconds.
Running Products.PloneTestCase.layer.PloneSite tests:
  Set up Products.PloneTestCase.layer.PloneSite in 4.025 seconds.
/home/stefan/autotest/temp/cache/Zope-2.10.11-final-py2.4/lib/python/OFS/subscribers.py:73: DeprecationWarning: Products.Archetypes.tests.test_classgen.Dummy.manage_afterAdd is discouraged. You should use event subscribers instead.
  DeprecationWarning)
/home/stefan/autotest/temp/cache/Zope-2.10.11-final-py2.4/lib/python/OFS/subscribers.py:73: DeprecationWarning: Products.Archetypes.tests.test_annotation.AnnDummy.manage_afterAdd is discouraged. You should use event subscribers instead.
  DeprecationWarning)
/home/stefan/autotest/temp/python24-zope210-cmf21-plone33next/eggs/Plone-3.3.4-py2.4.egg/Products/CMFPlone/utils.py:93: DeprecationWarning: The context parameter for isDefaultPage is deprecated and will be removed in Plone 4.
  DeprecationWarning, 1)
/home/stefan/autotest/temp/cache/Zope-2.10.11-final-py2.4/lib/python/OFS/subscribers.py:73: DeprecationWarning: Products.Archetypes.tests.test_event.Dummy.manage_afterAdd is discouraged. You should use event subscribers instead.
  DeprecationWarning)


Failure in test testSame (Products.PortalTransforms.tests.test_transforms.TransformTestSubclass)
Traceback (most recent call last):
  File "/home/stefan/autotest/temp/cache/Zope-2.10.11-final-py2.4/lib/python/Testing/ZopeTestCase/profiler.py", line 98, in __call__
    testMethod()
  File "/home/stefan/autotest/temp/python24-zope210-cmf21-plone33next/eggs/Products.PortalTransforms-1.6.6-py2.4.egg/Products/PortalTransforms/tests/test_transforms.py", line 67, in testSame
    self.do_convert(filename=self.input)
  File "/home/stefan/autotest/temp/python24-zope210-cmf21-plone33next/eggs/Products.PortalTransforms-1.6.6-py2.4.egg/Products/PortalTransforms/tests/test_transforms.py", line 58, in do_convert
    '[%s]\n\n!=\n\n[%s]\n\nIN %s(%s)' % (
  File "/usr/local/python2.4/lib/python2.4/unittest.py", line 333, in failUnlessEqual
    raise self.failureException, \
AssertionError: [<A name=1></a>Chapter&nbsp;44<br>Writing&nbsp;Basic&nbsp;Unit&nbsp;Tests<br>Difficulty<br>Newcomer<br>Skills<br>•&nbsp;All&nbsp;you&nbsp;need&nbsp;to&nbsp;know&nbsp;is&nbsp;some&nbsp;Python.<br>Problem/Task<br>As&nbsp;you&nbsp;know&nbsp;by&nbsp;now,&nbsp;Zope&nbsp;3&nbsp;gains&nbsp;its&nbsp;incredible&nbsp;stability&nbsp;from&nbsp;testing&nbsp;any&nbsp;code&nbsp;in&nbsp;great&nbsp;detail.&nbsp;The<br>currently&nbsp;most&nbsp;common&nbsp;method&nbsp;is&nbsp;to&nbsp;write&nbsp;unit&nbsp;tests.&nbsp;This&nbsp;chapter&nbsp;introduces&nbsp;unit&nbsp;tests&nbsp;–&nbsp;which<br>are&nbsp;Zope&nbsp;3&nbsp;independent&nbsp;–&nbsp;and&nbsp;introduces&nbsp;some&nbsp;of&nbsp;the&nbsp;subtleties.<br>Solution<br>44.1<br>Implementing&nbsp;the&nbsp;Sample&nbsp;Class<br>Before&nbsp;we&nbsp;can&nbsp;write&nbsp;tests,&nbsp;we&nbsp;have&nbsp;to&nbsp;write&nbsp;some&nbsp;code&nbsp;that&nbsp;we&nbsp;can&nbsp;test.&nbsp;Here,&nbsp;we&nbsp;will&nbsp;implement<br>a&nbsp;simple&nbsp;class&nbsp;called&nbsp;Sample&nbsp;with&nbsp;a&nbsp;public&nbsp;attribute&nbsp;title&nbsp;and&nbsp;description&nbsp;that&nbsp;is&nbsp;accessed<br>via&nbsp;getDescription()&nbsp;and&nbsp;mutated&nbsp;using&nbsp;setDescription().&nbsp;Further,&nbsp;the&nbsp;description&nbsp;must&nbsp;be<br>either&nbsp;a&nbsp;regular&nbsp;or&nbsp;unicode&nbsp;string.<br>Since&nbsp;this&nbsp;code&nbsp;will&nbsp;not&nbsp;depend&nbsp;on&nbsp;Zope,&nbsp;open&nbsp;a&nbsp;file&nbsp;named&nbsp;test&nbsp;sample.py&nbsp;anywhere&nbsp;and&nbsp;add<br>the&nbsp;following&nbsp;class:<br>1&nbsp;Sample(object):<br>2<br>&quot;&quot;&quot;A&nbsp;trivial&nbsp;Sample&nbsp;object.&quot;&quot;&quot;<br>3<br>4<br>title&nbsp;=&nbsp;None<br>5<br>6<br>def&nbsp;__init__(self):<br>7<br>&quot;&quot;&quot;Initialize&nbsp;object.&quot;&quot;&quot;<br>8<br>self._description&nbsp;=&nbsp;’’<br>9<br>1<br><hr><A name=2></a>2<br>CHAPTER&nbsp;44.&nbsp;WRITING&nbsp;BASIC&nbsp;UNIT&nbsp;TESTS<br>10<br>def&nbsp;setDescription(self,&nbsp;value):<br>11<br>&quot;&quot;&quot;Change&nbsp;the&nbsp;value&nbsp;of&nbsp;the&nbsp;description.&quot;&quot;&quot;<br>12<br>assert&nbsp;isinstance(value,&nbsp;(str,&nbsp;unicode))<br>13<br>self._description&nbsp;=&nbsp;value<br>14<br>15<br>def&nbsp;getDescription(self):<br>16<br>&quot;&quot;&quot;Change&nbsp;the&nbsp;value&nbsp;of&nbsp;the&nbsp;description.&quot;&quot;&quot;<br>17<br>return&nbsp;self._description<br>Line&nbsp;4:&nbsp;The&nbsp;title&nbsp;is&nbsp;just&nbsp;publicly&nbsp;declared&nbsp;and&nbsp;a&nbsp;value&nbsp;of&nbsp;None&nbsp;is&nbsp;given.&nbsp;Therefore&nbsp;this&nbsp;is&nbsp;just<br>a&nbsp;regular&nbsp;attribute.<br>Line&nbsp;8:&nbsp;The&nbsp;actual&nbsp;description&nbsp;string&nbsp;will&nbsp;be&nbsp;stored&nbsp;in&nbsp;description.<br>Line&nbsp;12:&nbsp;Make&nbsp;sure&nbsp;that&nbsp;the&nbsp;description&nbsp;is&nbsp;only&nbsp;a&nbsp;regular&nbsp;or&nbsp;unicode&nbsp;string,&nbsp;like&nbsp;it&nbsp;was&nbsp;stated&nbsp;in<br>the&nbsp;requirements.<br>If&nbsp;you&nbsp;wish&nbsp;you&nbsp;can&nbsp;now&nbsp;manually&nbsp;test&nbsp;the&nbsp;class&nbsp;with&nbsp;the&nbsp;interactive&nbsp;Python&nbsp;shell.&nbsp;Just&nbsp;start<br>Python&nbsp;by&nbsp;entering&nbsp;python&nbsp;in&nbsp;your&nbsp;shell&nbsp;prompt.&nbsp;Note&nbsp;that&nbsp;you&nbsp;should&nbsp;be&nbsp;in&nbsp;the&nbsp;directory&nbsp;in<br>which&nbsp;test&nbsp;sample.py&nbsp;is&nbsp;located&nbsp;when&nbsp;starting&nbsp;Python&nbsp;(an&nbsp;alternative&nbsp;is&nbsp;of&nbsp;course&nbsp;to&nbsp;specify&nbsp;the<br>directory&nbsp;in&nbsp;your&nbsp;PYTHONPATH.)<br>1&nbsp;&gt;&gt;&gt;&nbsp;from&nbsp;test_sample&nbsp;import&nbsp;Sample<br>2&nbsp;&gt;&gt;&gt;&nbsp;sample&nbsp;=&nbsp;Sample()<br>3&nbsp;&gt;&gt;&gt;&nbsp;print&nbsp;sample.title<br>4&nbsp;None<br>5&nbsp;&gt;&gt;&gt;&nbsp;sample.title&nbsp;=&nbsp;’Title’<br>6&nbsp;&gt;&gt;&gt;&nbsp;print&nbsp;sample.title<br>7&nbsp;Title<br>8&nbsp;&gt;&gt;&gt;&nbsp;print&nbsp;sample.getDescription()<br>9<br>10&nbsp;&gt;&gt;&gt;&nbsp;sample.setDescription(’Hello&nbsp;World’)<br>11&nbsp;&gt;&gt;&gt;&nbsp;print&nbsp;sample.getDescription()<br>12&nbsp;Hello&nbsp;World<br>13&nbsp;&gt;&gt;&gt;&nbsp;sample.setDescription(None)<br>14&nbsp;Traceback&nbsp;(most&nbsp;recent&nbsp;call&nbsp;last):<br>15<br>File&nbsp;&quot;&lt;stdin&gt;&quot;,&nbsp;line&nbsp;1,&nbsp;in&nbsp;?<br>16<br>File&nbsp;&quot;test_sample.py&quot;,&nbsp;line&nbsp;31,&nbsp;in&nbsp;setDescription<br>17<br>assert&nbsp;isinstance(value,&nbsp;(str,&nbsp;unicode))<br>18&nbsp;AssertionError<br>As&nbsp;you&nbsp;can&nbsp;see&nbsp;in&nbsp;the&nbsp;last&nbsp;test,&nbsp;non-string&nbsp;object&nbsp;types&nbsp;are&nbsp;not&nbsp;allowed&nbsp;as&nbsp;descriptions&nbsp;and&nbsp;an<br>AssertionError&nbsp;is&nbsp;raised.<br>44.2<br>Writing&nbsp;the&nbsp;Unit&nbsp;Tests<br>The&nbsp;goal&nbsp;of&nbsp;writing&nbsp;the&nbsp;unit&nbsp;tests&nbsp;is&nbsp;to&nbsp;convert&nbsp;this&nbsp;informal,&nbsp;manual,&nbsp;and&nbsp;interactive&nbsp;testing&nbsp;session<br>into&nbsp;a&nbsp;formal&nbsp;test&nbsp;class.&nbsp;Python&nbsp;provides&nbsp;already&nbsp;a&nbsp;module&nbsp;called&nbsp;unittest&nbsp;for&nbsp;this&nbsp;purpose,&nbsp;which<br>is&nbsp;a&nbsp;port&nbsp;of&nbsp;the&nbsp;Java-based&nbsp;unit&nbsp;testing&nbsp;product,&nbsp;JUnit,&nbsp;by&nbsp;Kent&nbsp;Beck&nbsp;and&nbsp;Erich&nbsp;Gamma.&nbsp;There&nbsp;are<br>three&nbsp;levels&nbsp;to&nbsp;the&nbsp;testing&nbsp;framework&nbsp;(this&nbsp;list&nbsp;deviates&nbsp;a&nbsp;bit&nbsp;from&nbsp;the&nbsp;original&nbsp;definitions&nbsp;as&nbsp;found<br>in&nbsp;the&nbsp;Python&nbsp;library&nbsp;documentation.&nbsp;1).<br>1&nbsp;http://www.python.org/doc/current/lib/module-unittest.html<br><hr><A name=3></a>44.2.&nbsp;WRITING&nbsp;THE&nbsp;UNIT&nbsp;TESTS<br>3<br>The&nbsp;smallest&nbsp;unit&nbsp;is&nbsp;obviously&nbsp;the&nbsp;“test”,&nbsp;which&nbsp;is&nbsp;a&nbsp;single&nbsp;method&nbsp;in&nbsp;a&nbsp;TestCase&nbsp;class&nbsp;that<br>tests&nbsp;the&nbsp;behavior&nbsp;of&nbsp;a&nbsp;small&nbsp;piece&nbsp;of&nbsp;code&nbsp;or&nbsp;a&nbsp;particular&nbsp;aspect&nbsp;of&nbsp;an&nbsp;implementation.&nbsp;The&nbsp;“test<br>case”&nbsp;is&nbsp;then&nbsp;a&nbsp;collection&nbsp;tests&nbsp;that&nbsp;share&nbsp;the&nbsp;same&nbsp;setup/inputs.&nbsp;On&nbsp;top&nbsp;of&nbsp;all&nbsp;of&nbsp;this&nbsp;sits&nbsp;the&nbsp;“test<br>suite”&nbsp;which&nbsp;is&nbsp;a&nbsp;collection&nbsp;of&nbsp;test&nbsp;cases&nbsp;and/or&nbsp;other&nbsp;test&nbsp;suites.&nbsp;Test&nbsp;suites&nbsp;combine&nbsp;tests&nbsp;that<br>should&nbsp;be&nbsp;executed&nbsp;together.&nbsp;With&nbsp;the&nbsp;correct&nbsp;setup&nbsp;(as&nbsp;shown&nbsp;in&nbsp;the&nbsp;example&nbsp;below),&nbsp;you&nbsp;can<br>then&nbsp;execute&nbsp;test&nbsp;suites.&nbsp;For&nbsp;large&nbsp;projects&nbsp;like&nbsp;Zope&nbsp;3,&nbsp;it&nbsp;is&nbsp;useful&nbsp;to&nbsp;know&nbsp;that&nbsp;there&nbsp;is&nbsp;also&nbsp;the<br>concept&nbsp;of&nbsp;a&nbsp;test&nbsp;runner,&nbsp;which&nbsp;manages&nbsp;the&nbsp;test&nbsp;run&nbsp;of&nbsp;all&nbsp;or&nbsp;a&nbsp;set&nbsp;of&nbsp;tests.&nbsp;The&nbsp;runner&nbsp;provides<br>useful&nbsp;feedback&nbsp;to&nbsp;the&nbsp;application,&nbsp;so&nbsp;that&nbsp;various&nbsp;user&nbsp;interaces&nbsp;can&nbsp;be&nbsp;developed&nbsp;on&nbsp;top&nbsp;of&nbsp;it.<br>But&nbsp;enough&nbsp;about&nbsp;the&nbsp;theory.&nbsp;In&nbsp;the&nbsp;following&nbsp;example,&nbsp;which&nbsp;you&nbsp;can&nbsp;simply&nbsp;put&nbsp;into&nbsp;the&nbsp;same<br>file&nbsp;as&nbsp;your&nbsp;code&nbsp;above,&nbsp;you&nbsp;will&nbsp;see&nbsp;a&nbsp;test&nbsp;in&nbsp;common&nbsp;Zope&nbsp;3&nbsp;style.<br>1&nbsp;import&nbsp;unittest<br>2<br>3&nbsp;class&nbsp;SampleTest(unittest.TestCase):<br>4<br>&quot;&quot;&quot;Test&nbsp;the&nbsp;Sample&nbsp;class&quot;&quot;&quot;<br>5<br>6<br>def&nbsp;test_title(self):<br>7<br>sample&nbsp;=&nbsp;Sample()<br>8<br>self.assertEqual(sample.title,&nbsp;None)<br>9<br>sample.title&nbsp;=&nbsp;’Sample&nbsp;Title’<br>10<br>self.assertEqual(sample.title,&nbsp;’Sample&nbsp;Title’)<br>11<br>12<br>def&nbsp;test_getDescription(self):<br>13<br>sample&nbsp;=&nbsp;Sample()<br>14<br>self.assertEqual(sample.getDescription(),&nbsp;’’)<br>15<br>sample._description&nbsp;=&nbsp;&quot;Description&quot;<br>16<br>self.assertEqual(sample.getDescription(),&nbsp;’Description’)<br>17<br>18<br>def&nbsp;test_setDescription(self):<br>19<br>sample&nbsp;=&nbsp;Sample()<br>20<br>self.assertEqual(sample._description,&nbsp;’’)<br>21<br>sample.setDescription(’Description’)<br>22<br>self.assertEqual(sample._description,&nbsp;’Description’)<br>23<br>sample.setDescription(u’Description2’)<br>24<br>self.assertEqual(sample._description,&nbsp;u’Description2’)<br>25<br>self.assertRaises(AssertionError,&nbsp;sample.setDescription,&nbsp;None)<br>26<br>27<br>28&nbsp;def&nbsp;test_suite():<br>29<br>return&nbsp;unittest.TestSuite((<br>30<br>unittest.makeSuite(SampleTest),<br>31<br>))<br>32<br>33&nbsp;if&nbsp;__name__&nbsp;==&nbsp;’__main__’:<br>34<br>unittest.main(defaultTest=’test_suite’)<br>Line&nbsp;3–4:&nbsp;We&nbsp;usually&nbsp;develop&nbsp;test&nbsp;classes&nbsp;which&nbsp;must&nbsp;inherit&nbsp;from&nbsp;TestCase.&nbsp;While&nbsp;often&nbsp;not<br>done,&nbsp;it&nbsp;is&nbsp;a&nbsp;good&nbsp;idea&nbsp;to&nbsp;give&nbsp;the&nbsp;class&nbsp;a&nbsp;meaningful&nbsp;docstring&nbsp;that&nbsp;describes&nbsp;the&nbsp;purpose&nbsp;of&nbsp;the<br>tests&nbsp;it&nbsp;includes.<br>Line&nbsp;6,&nbsp;12&nbsp;&amp;&nbsp;18:&nbsp;When&nbsp;a&nbsp;test&nbsp;case&nbsp;is&nbsp;run,&nbsp;a&nbsp;method&nbsp;called&nbsp;runTests()&nbsp;is&nbsp;executed.&nbsp;While&nbsp;it<br>is&nbsp;possible&nbsp;to&nbsp;overrride&nbsp;this&nbsp;method&nbsp;to&nbsp;run&nbsp;tests&nbsp;differently,&nbsp;the&nbsp;default&nbsp;option&nbsp;will&nbsp;look&nbsp;for&nbsp;any<br>method&nbsp;whose&nbsp;name&nbsp;starts&nbsp;with&nbsp;test&nbsp;and&nbsp;execute&nbsp;it&nbsp;as&nbsp;a&nbsp;single&nbsp;test.&nbsp;This&nbsp;way&nbsp;we&nbsp;can&nbsp;create<br>a&nbsp;“test&nbsp;method”&nbsp;for&nbsp;each&nbsp;aspect,&nbsp;method,&nbsp;function&nbsp;or&nbsp;property&nbsp;of&nbsp;the&nbsp;code&nbsp;to&nbsp;be&nbsp;tested.&nbsp;This<br>default&nbsp;is&nbsp;very&nbsp;sensible&nbsp;and&nbsp;is&nbsp;used&nbsp;everywhere&nbsp;in&nbsp;Zope&nbsp;3.<br><hr><A name=4></a>4<br>CHAPTER&nbsp;44.&nbsp;WRITING&nbsp;BASIC&nbsp;UNIT&nbsp;TESTS<br>Note&nbsp;that&nbsp;there&nbsp;is&nbsp;no&nbsp;docstring&nbsp;for&nbsp;test&nbsp;methods.&nbsp;This&nbsp;is&nbsp;intentional.&nbsp;If&nbsp;a&nbsp;docstring&nbsp;is&nbsp;specified,<br>it&nbsp;is&nbsp;used&nbsp;instead&nbsp;of&nbsp;the&nbsp;method&nbsp;name&nbsp;to&nbsp;identify&nbsp;the&nbsp;test.&nbsp;When&nbsp;specifying&nbsp;a&nbsp;docstring,&nbsp;we&nbsp;have<br>noticed&nbsp;that&nbsp;it&nbsp;is&nbsp;very&nbsp;difficult&nbsp;to&nbsp;identify&nbsp;the&nbsp;test&nbsp;later;&nbsp;therefore&nbsp;the&nbsp;method&nbsp;name&nbsp;is&nbsp;a&nbsp;much<br>better&nbsp;choice.<br>Line&nbsp;8,&nbsp;10,&nbsp;14,&nbsp;.&nbsp;.&nbsp;.&nbsp;:&nbsp;The&nbsp;TestCase&nbsp;class&nbsp;implements&nbsp;a&nbsp;handful&nbsp;of&nbsp;methods&nbsp;that&nbsp;aid&nbsp;you&nbsp;with&nbsp;the<br>testing.&nbsp;Here&nbsp;are&nbsp;some&nbsp;of&nbsp;the&nbsp;most&nbsp;frequently&nbsp;used&nbsp;ones.&nbsp;For&nbsp;a&nbsp;complete&nbsp;list&nbsp;see&nbsp;the&nbsp;standard<br>Python&nbsp;documentation&nbsp;referenced&nbsp;above.<br>•&nbsp;assertEqual(first,second[,msg])<br>Checks&nbsp;whether&nbsp;the&nbsp;first&nbsp;and&nbsp;second&nbsp;value&nbsp;are&nbsp;equal.&nbsp;If&nbsp;the&nbsp;test&nbsp;fails,&nbsp;the&nbsp;msg&nbsp;or&nbsp;None<br>is&nbsp;returned.<br>•&nbsp;assertNotEqual(first,second[,msg])<br>This&nbsp;is&nbsp;simply&nbsp;the&nbsp;opposite&nbsp;to&nbsp;assertEqual()&nbsp;by&nbsp;checking&nbsp;for&nbsp;non-equality.<br>•&nbsp;assertRaises(exception,callable,...)<br>You&nbsp;expect&nbsp;the&nbsp;callable&nbsp;to&nbsp;raise&nbsp;exception&nbsp;when&nbsp;executed.&nbsp;After&nbsp;the&nbsp;callable&nbsp;you&nbsp;can<br>specify&nbsp;any&nbsp;amount&nbsp;of&nbsp;positional&nbsp;and&nbsp;keyword&nbsp;arguments&nbsp;for&nbsp;the&nbsp;callable.&nbsp;If&nbsp;you&nbsp;expect<br>a&nbsp;group&nbsp;of&nbsp;exceptions&nbsp;from&nbsp;the&nbsp;execution,&nbsp;you&nbsp;can&nbsp;make&nbsp;exception&nbsp;a&nbsp;tuple&nbsp;of&nbsp;possible<br>exceptions.<br>•&nbsp;assert&nbsp;(expr[,msg])<br>Assert&nbsp;checks&nbsp;whether&nbsp;the&nbsp;specified&nbsp;expression&nbsp;executes&nbsp;correctly.&nbsp;If&nbsp;not,&nbsp;the&nbsp;test&nbsp;fails&nbsp;and<br>msg&nbsp;or&nbsp;None&nbsp;is&nbsp;returned.<br>•&nbsp;failUnlessEqual()<br>This&nbsp;testing&nbsp;method&nbsp;is&nbsp;equivalent&nbsp;to&nbsp;assertEqual().<br>•&nbsp;failUnless(expr[,msg])<br>This&nbsp;method&nbsp;is&nbsp;equivalent&nbsp;to&nbsp;assert&nbsp;(expr[,msg]).<br>•&nbsp;failif()<br>This&nbsp;is&nbsp;the&nbsp;opposite&nbsp;to&nbsp;failUnless().<br>•&nbsp;fail([msg])<br>Fails&nbsp;the&nbsp;running&nbsp;test&nbsp;without&nbsp;any&nbsp;evaluation.&nbsp;This&nbsp;is&nbsp;commonly&nbsp;used&nbsp;when&nbsp;testing&nbsp;various<br>possible&nbsp;execution&nbsp;paths&nbsp;at&nbsp;once&nbsp;and&nbsp;you&nbsp;would&nbsp;like&nbsp;to&nbsp;signify&nbsp;a&nbsp;failure&nbsp;if&nbsp;an&nbsp;improper&nbsp;path<br>was&nbsp;taken.<br>Line&nbsp;6–10:&nbsp;This&nbsp;method&nbsp;tests&nbsp;the&nbsp;title&nbsp;attribute&nbsp;of&nbsp;the&nbsp;Sample&nbsp;class.&nbsp;The&nbsp;first&nbsp;test&nbsp;should<br>be&nbsp;of&nbsp;course&nbsp;that&nbsp;the&nbsp;attribute&nbsp;exists&nbsp;and&nbsp;has&nbsp;the&nbsp;expected&nbsp;initial&nbsp;value&nbsp;(line&nbsp;8).&nbsp;Then&nbsp;the&nbsp;title<br>attribute&nbsp;is&nbsp;changed&nbsp;and&nbsp;we&nbsp;check&nbsp;whether&nbsp;the&nbsp;value&nbsp;was&nbsp;really&nbsp;stored.&nbsp;This&nbsp;might&nbsp;seem&nbsp;like<br>overkill,&nbsp;but&nbsp;later&nbsp;you&nbsp;might&nbsp;change&nbsp;the&nbsp;title&nbsp;in&nbsp;a&nbsp;way&nbsp;that&nbsp;it&nbsp;uses&nbsp;properties&nbsp;instead.&nbsp;Then&nbsp;it<br>becomes&nbsp;very&nbsp;important&nbsp;to&nbsp;check&nbsp;whether&nbsp;this&nbsp;test&nbsp;still&nbsp;passes.<br>Line&nbsp;12–16:&nbsp;First&nbsp;we&nbsp;simply&nbsp;check&nbsp;that&nbsp;getDescription()&nbsp;returns&nbsp;the&nbsp;correct&nbsp;default&nbsp;value.<br>Since&nbsp;we&nbsp;do&nbsp;not&nbsp;want&nbsp;to&nbsp;use&nbsp;other&nbsp;API&nbsp;calls&nbsp;like&nbsp;setDescription()&nbsp;we&nbsp;set&nbsp;a&nbsp;new&nbsp;value&nbsp;of&nbsp;the<br>description&nbsp;via&nbsp;the&nbsp;implementation-internal&nbsp;description&nbsp;attribute&nbsp;(line&nbsp;15).&nbsp;This&nbsp;is&nbsp;okay!&nbsp;Unit<br>tests&nbsp;can&nbsp;make&nbsp;use&nbsp;of&nbsp;implementation-specific&nbsp;attributes&nbsp;and&nbsp;methods.&nbsp;Finally&nbsp;we&nbsp;just&nbsp;check&nbsp;that<br>the&nbsp;correct&nbsp;value&nbsp;is&nbsp;returned.<br><hr><A name=5></a>44.3.&nbsp;RUNNING&nbsp;THE&nbsp;TESTS<br>5<br>Line&nbsp;18–25:&nbsp;On&nbsp;line&nbsp;21–24&nbsp;it&nbsp;is&nbsp;checked&nbsp;that&nbsp;both&nbsp;regular&nbsp;and&nbsp;unicode&nbsp;strings&nbsp;are&nbsp;set&nbsp;correctly.<br>In&nbsp;the&nbsp;last&nbsp;line&nbsp;of&nbsp;the&nbsp;test&nbsp;we&nbsp;make&nbsp;sure&nbsp;that&nbsp;no&nbsp;other&nbsp;type&nbsp;of&nbsp;objects&nbsp;can&nbsp;be&nbsp;set&nbsp;as&nbsp;a&nbsp;description<br>and&nbsp;that&nbsp;an&nbsp;error&nbsp;is&nbsp;raised.<br>28–31:&nbsp;This&nbsp;method&nbsp;returns&nbsp;a&nbsp;test&nbsp;suite&nbsp;that&nbsp;includes&nbsp;all&nbsp;test&nbsp;cases&nbsp;created&nbsp;in&nbsp;this&nbsp;module.&nbsp;It&nbsp;is<br>used&nbsp;by&nbsp;the&nbsp;Zope&nbsp;3&nbsp;test&nbsp;runner&nbsp;when&nbsp;it&nbsp;picks&nbsp;up&nbsp;all&nbsp;available&nbsp;tests.&nbsp;You&nbsp;would&nbsp;basically&nbsp;add&nbsp;the<br>line&nbsp;unittest.makeSuite(TestCaseClass)&nbsp;for&nbsp;each&nbsp;additional&nbsp;test&nbsp;case.<br>33–34:&nbsp;In&nbsp;order&nbsp;to&nbsp;make&nbsp;the&nbsp;test&nbsp;module&nbsp;runnable&nbsp;by&nbsp;itself,&nbsp;you&nbsp;can&nbsp;execute&nbsp;unittest.main()<br>when&nbsp;the&nbsp;module&nbsp;is&nbsp;run.<br>44.3<br>Running&nbsp;the&nbsp;Tests<br>You&nbsp;can&nbsp;run&nbsp;the&nbsp;test&nbsp;by&nbsp;simply&nbsp;calling&nbsp;pythontest&nbsp;sample.py&nbsp;from&nbsp;the&nbsp;directory&nbsp;you&nbsp;saved&nbsp;the<br>file&nbsp;in.&nbsp;Here&nbsp;is&nbsp;the&nbsp;result&nbsp;you&nbsp;should&nbsp;see:<br>.<br>--------------------------------------------------------------------<br>n&nbsp;3&nbsp;tests&nbsp;in&nbsp;0.001s<br>The&nbsp;three&nbsp;dots&nbsp;represent&nbsp;the&nbsp;three&nbsp;tests&nbsp;that&nbsp;were&nbsp;run.&nbsp;If&nbsp;a&nbsp;test&nbsp;had&nbsp;failed,&nbsp;it&nbsp;would&nbsp;have&nbsp;been<br>reported&nbsp;pointing&nbsp;out&nbsp;the&nbsp;failing&nbsp;test&nbsp;and&nbsp;providing&nbsp;a&nbsp;small&nbsp;traceback.<br>When&nbsp;using&nbsp;the&nbsp;default&nbsp;Zope&nbsp;3&nbsp;test&nbsp;runner,&nbsp;tests&nbsp;will&nbsp;be&nbsp;picked&nbsp;up&nbsp;as&nbsp;long&nbsp;as&nbsp;they&nbsp;follow&nbsp;some<br>conventions.<br>•&nbsp;The&nbsp;tests&nbsp;must&nbsp;either&nbsp;be&nbsp;in&nbsp;a&nbsp;package&nbsp;or&nbsp;be&nbsp;a&nbsp;module&nbsp;called&nbsp;tests.<br>•&nbsp;If&nbsp;tests&nbsp;is&nbsp;a&nbsp;package,&nbsp;then&nbsp;all&nbsp;test&nbsp;modules&nbsp;inside&nbsp;must&nbsp;also&nbsp;have&nbsp;a&nbsp;name&nbsp;starting&nbsp;with&nbsp;test,<br>as&nbsp;it&nbsp;is&nbsp;the&nbsp;case&nbsp;with&nbsp;our&nbsp;name&nbsp;test&nbsp;sample.py.<br>•&nbsp;The&nbsp;test&nbsp;module&nbsp;must&nbsp;be&nbsp;somewhere&nbsp;in&nbsp;the&nbsp;Zope&nbsp;3&nbsp;source&nbsp;tree,&nbsp;since&nbsp;the&nbsp;test&nbsp;runner&nbsp;looks<br>only&nbsp;for&nbsp;files&nbsp;there.<br>In&nbsp;our&nbsp;case,&nbsp;you&nbsp;could&nbsp;simply&nbsp;create&nbsp;a&nbsp;tests&nbsp;package&nbsp;in&nbsp;ZOPE3/src&nbsp;(do&nbsp;not&nbsp;forget&nbsp;the<br>init&nbsp;.<br>py&nbsp;file).&nbsp;Then&nbsp;place&nbsp;the&nbsp;test&nbsp;sample.py&nbsp;file&nbsp;into&nbsp;this&nbsp;directory.<br>You&nbsp;you&nbsp;can&nbsp;use&nbsp;the&nbsp;test&nbsp;runner&nbsp;to&nbsp;run&nbsp;only&nbsp;the&nbsp;sample&nbsp;tests&nbsp;as&nbsp;follows&nbsp;from&nbsp;the&nbsp;Zope&nbsp;3&nbsp;root<br>directory:<br>python&nbsp;test.py&nbsp;-vp&nbsp;tests.test_sample<br>The&nbsp;-v&nbsp;option&nbsp;stands&nbsp;for&nbsp;verbose&nbsp;mode,&nbsp;so&nbsp;that&nbsp;detailed&nbsp;information&nbsp;about&nbsp;a&nbsp;test&nbsp;failure&nbsp;is<br>provided.&nbsp;The&nbsp;-p&nbsp;option&nbsp;enables&nbsp;a&nbsp;progress&nbsp;bar&nbsp;that&nbsp;tells&nbsp;you&nbsp;how&nbsp;many&nbsp;tests&nbsp;out&nbsp;of&nbsp;all&nbsp;have&nbsp;been<br>completed.&nbsp;There&nbsp;are&nbsp;many&nbsp;more&nbsp;options&nbsp;that&nbsp;can&nbsp;be&nbsp;specified.&nbsp;You&nbsp;can&nbsp;get&nbsp;a&nbsp;full&nbsp;list&nbsp;of&nbsp;them&nbsp;with<br>the&nbsp;option&nbsp;-h:&nbsp;pythontest.py-h.<br>The&nbsp;output&nbsp;of&nbsp;the&nbsp;call&nbsp;above&nbsp;is&nbsp;as&nbsp;follows:<br>nfiguration&nbsp;file&nbsp;found.<br>nning&nbsp;UNIT&nbsp;tests&nbsp;at&nbsp;level&nbsp;1<br>nning&nbsp;UNIT&nbsp;tests&nbsp;from&nbsp;/opt/zope/Zope3<br>3/3&nbsp;(100.0%):&nbsp;test_title&nbsp;(tests.test_sample.SampleTest)<br>--------------------------------------------------------------------<br>n&nbsp;3&nbsp;tests&nbsp;in&nbsp;0.002s<br><hr><A name=6></a>6<br>CHAPTER&nbsp;44.&nbsp;WRITING&nbsp;BASIC&nbsp;UNIT&nbsp;TESTS<br>nning&nbsp;FUNCTIONAL&nbsp;tests&nbsp;at&nbsp;level&nbsp;1<br>nning&nbsp;FUNCTIONAL&nbsp;tests&nbsp;from&nbsp;/opt/zope/Zope3<br>--------------------------------------------------------------------<br>n&nbsp;0&nbsp;tests&nbsp;in&nbsp;0.000s<br>Line&nbsp;1:&nbsp;The&nbsp;test&nbsp;runner&nbsp;uses&nbsp;a&nbsp;configuration&nbsp;file&nbsp;for&nbsp;some&nbsp;setup.&nbsp;This&nbsp;allows&nbsp;developers&nbsp;to&nbsp;use<br>the&nbsp;test&nbsp;runner&nbsp;for&nbsp;other&nbsp;projects&nbsp;as&nbsp;well.&nbsp;This&nbsp;message&nbsp;simply&nbsp;tells&nbsp;us&nbsp;that&nbsp;the&nbsp;configuration&nbsp;file<br>was&nbsp;found.<br>Line&nbsp;2–8:&nbsp;The&nbsp;unit&nbsp;tests&nbsp;are&nbsp;run.&nbsp;On&nbsp;line&nbsp;4&nbsp;you&nbsp;can&nbsp;see&nbsp;the&nbsp;progress&nbsp;bar.<br>Line&nbsp;9–15:&nbsp;The&nbsp;functional&nbsp;tests&nbsp;are&nbsp;run,&nbsp;since&nbsp;the&nbsp;default&nbsp;test&nbsp;runner&nbsp;runs&nbsp;both&nbsp;types&nbsp;of&nbsp;tests.<br>Since&nbsp;we&nbsp;do&nbsp;not&nbsp;have&nbsp;any&nbsp;functional&nbsp;tests&nbsp;in&nbsp;the&nbsp;specified&nbsp;module,&nbsp;there&nbsp;are&nbsp;no&nbsp;tests&nbsp;to&nbsp;run.&nbsp;To<br>just&nbsp;run&nbsp;the&nbsp;unit&nbsp;tests,&nbsp;use&nbsp;option&nbsp;-u&nbsp;and&nbsp;-f&nbsp;for&nbsp;just&nbsp;running&nbsp;the&nbsp;functional&nbsp;tests.&nbsp;See&nbsp;“Writing<br>Functional&nbsp;Tests”&nbsp;for&nbsp;more&nbsp;detials&nbsp;on&nbsp;functional&nbsp;tests.<br><hr><A name=7></a>44.3.&nbsp;RUNNING&nbsp;THE&nbsp;TESTS<br>7<br>Exercises<br>1.&nbsp;It&nbsp;is&nbsp;not&nbsp;very&nbsp;common&nbsp;to&nbsp;do&nbsp;the&nbsp;setup&nbsp;–&nbsp;in&nbsp;our&nbsp;case&nbsp;sample=Sample()&nbsp;–&nbsp;in&nbsp;every&nbsp;test<br>method.&nbsp;Instead&nbsp;there&nbsp;exists&nbsp;a&nbsp;method&nbsp;called&nbsp;setUp()&nbsp;and&nbsp;its&nbsp;counterpart&nbsp;tearDown&nbsp;that<br>are&nbsp;run&nbsp;before&nbsp;and&nbsp;after&nbsp;each&nbsp;test,&nbsp;respectively.&nbsp;Change&nbsp;the&nbsp;test&nbsp;code&nbsp;above,&nbsp;so&nbsp;that&nbsp;it&nbsp;uses<br>the&nbsp;setUp()&nbsp;method.&nbsp;In&nbsp;later&nbsp;chapters&nbsp;and&nbsp;the&nbsp;rest&nbsp;of&nbsp;the&nbsp;book&nbsp;we&nbsp;will&nbsp;frequently&nbsp;use&nbsp;this<br>method&nbsp;of&nbsp;setting&nbsp;up&nbsp;tests.<br>2.&nbsp;Currently&nbsp;the&nbsp;test&nbsp;setDescription()&nbsp;test&nbsp;only&nbsp;verifies&nbsp;that&nbsp;None&nbsp;is&nbsp;not&nbsp;allowed&nbsp;as&nbsp;input<br>value.<br>(a)&nbsp;Improve&nbsp;the&nbsp;test,&nbsp;so&nbsp;that&nbsp;all&nbsp;other&nbsp;builtin&nbsp;types&nbsp;are&nbsp;tested&nbsp;as&nbsp;well.<br>(b)&nbsp;Also,&nbsp;make&nbsp;sure&nbsp;that&nbsp;any&nbsp;objects&nbsp;inheriting&nbsp;from&nbsp;str&nbsp;or&nbsp;unicode&nbsp;pass&nbsp;as&nbsp;valid&nbsp;values.<br><hr>]

!=

[<A name=1></a>Chapter 44<br>Writing Basic Unit Tests<br>Difficulty<br>Newcomer<br>Skills<br>• All you need to know is some Python.<br>Problem/Task<br>As you know by now, Zope 3 gains its incredible stability from testing any code in great detail. The<br>currently most common method is to write unit tests. This chapter introduces unit tests – which<br>are Zope 3 independent – and introduces some of the subtleties.<br>Solution<br>44.1<br>Implementing the Sample Class<br>Before we can write tests, we have to write some code that we can test. Here, we will implement<br>a simple class called Sample with a public attribute title and description that is accessed<br>via getDescription() and mutated using setDescription(). Further, the description must be<br>either a regular or unicode string.<br>Since this code will not depend on Zope, open a file named test sample.py anywhere and add<br>the following class:<br>1 Sample(object):<br>2<br>&quot;&quot;&quot;A trivial Sample object.&quot;&quot;&quot;<br>3<br>4<br>title = None<br>5<br>6<br>def __init__(self):<br>7<br>&quot;&quot;&quot;Initialize object.&quot;&quot;&quot;<br>8<br>self._description = ’’<br>9<br>1<br><hr><A name=2></a>2<br>CHAPTER 44. WRITING BASIC UNIT TESTS<br>10<br>def setDescription(self, value):<br>11<br>&quot;&quot;&quot;Change the value of the description.&quot;&quot;&quot;<br>12<br>assert isinstance(value, (str, unicode))<br>13<br>self._description = value<br>14<br>15<br>def getDescription(self):<br>16<br>&quot;&quot;&quot;Change the value of the description.&quot;&quot;&quot;<br>17<br>return self._description<br>Line 4: The title is just publicly declared and a value of None is given. Therefore this is just<br>a regular attribute.<br>Line 8: The actual description string will be stored in description.<br>Line 12: Make sure that the description is only a regular or unicode string, like it was stated in<br>the requirements.<br>If you wish you can now manually test the class with the interactive Python shell. Just start<br>Python by entering python in your shell prompt. Note that you should be in the directory in<br>which test sample.py is located when starting Python (an alternative is of course to specify the<br>directory in your PYTHONPATH.)<br>1 &gt;&gt;&gt; from test_sample import Sample<br>2 &gt;&gt;&gt; sample = Sample()<br>3 &gt;&gt;&gt; print sample.title<br>4 None<br>5 &gt;&gt;&gt; sample.title = ’Title’<br>6 &gt;&gt;&gt; print sample.title<br>7 Title<br>8 &gt;&gt;&gt; print sample.getDescription()<br>9<br>10 &gt;&gt;&gt; sample.setDescription(’Hello World’)<br>11 &gt;&gt;&gt; print sample.getDescription()<br>12 Hello World<br>13 &gt;&gt;&gt; sample.setDescription(None)<br>14 Traceback (most recent call last):<br>15<br>File &quot;&lt;stdin&gt;&quot;, line 1, in ?<br>16<br>File &quot;test_sample.py&quot;, line 31, in setDescription<br>17<br>assert isinstance(value, (str, unicode))<br>18 AssertionError<br>As you can see in the last test, non-string object types are not allowed as descriptions and an<br>AssertionError is raised.<br>44.2<br>Writing the Unit Tests<br>The goal of writing the unit tests is to convert this informal, manual, and interactive testing session<br>into a formal test class. Python provides already a module called unittest for this purpose, which<br>is a port of the Java-based unit testing product, JUnit, by Kent Beck and Erich Gamma. There are<br>three levels to the testing framework (this list deviates a bit from the original definitions as found<br>in the Python library documentation. 1).<br>1 http://www.python.org/doc/current/lib/module-unittest.html<br><hr><A name=3></a>44.2. WRITING THE UNIT TESTS<br>3<br>The smallest unit is obviously the “test”, which is a single method in a TestCase class that<br>tests the behavior of a small piece of code or a particular aspect of an implementation. The “test<br>case” is then a collection tests that share the same setup/inputs. On top of all of this sits the “test<br>suite” which is a collection of test cases and/or other test suites. Test suites combine tests that<br>should be executed together. With the correct setup (as shown in the example below), you can<br>then execute test suites. For large projects like Zope 3, it is useful to know that there is also the<br>concept of a test runner, which manages the test run of all or a set of tests. The runner provides<br>useful feedback to the application, so that various user interaces can be developed on top of it.<br>But enough about the theory. In the following example, which you can simply put into the same<br>file as your code above, you will see a test in common Zope 3 style.<br>1 import unittest<br>2<br>3 class SampleTest(unittest.TestCase):<br>4<br>&quot;&quot;&quot;Test the Sample class&quot;&quot;&quot;<br>5<br>6<br>def test_title(self):<br>7<br>sample = Sample()<br>8<br>self.assertEqual(sample.title, None)<br>9<br>sample.title = ’Sample Title’<br>10<br>self.assertEqual(sample.title, ’Sample Title’)<br>11<br>12<br>def test_getDescription(self):<br>13<br>sample = Sample()<br>14<br>self.assertEqual(sample.getDescription(), ’’)<br>15<br>sample._description = &quot;Description&quot;<br>16<br>self.assertEqual(sample.getDescription(), ’Description’)<br>17<br>18<br>def test_setDescription(self):<br>19<br>sample = Sample()<br>20<br>self.assertEqual(sample._description, ’’)<br>21<br>sample.setDescription(’Description’)<br>22<br>self.assertEqual(sample._description, ’Description’)<br>23<br>sample.setDescription(u’Description2’)<br>24<br>self.assertEqual(sample._description, u’Description2’)<br>25<br>self.assertRaises(AssertionError, sample.setDescription, None)<br>26<br>27<br>28 def test_suite():<br>29<br>return unittest.TestSuite((<br>30<br>unittest.makeSuite(SampleTest),<br>31<br>))<br>32<br>33 if __name__ == ’__main__’:<br>34<br>unittest.main(defaultTest=’test_suite’)<br>Line 3–4: We usually develop test classes which must inherit from TestCase. While often not<br>done, it is a good idea to give the class a meaningful docstring that describes the purpose of the<br>tests it includes.<br>Line 6, 12 &amp; 18: When a test case is run, a method called runTests() is executed. While it<br>is possible to overrride this method to run tests differently, the default option will look for any<br>method whose name starts with test and execute it as a single test. This way we can create<br>a “test method” for each aspect, method, function or property of the code to be tested. This<br>default is very sensible and is used everywhere in Zope 3.<br><hr><A name=4></a>4<br>CHAPTER 44. WRITING BASIC UNIT TESTS<br>Note that there is no docstring for test methods. This is intentional. If a docstring is specified,<br>it is used instead of the method name to identify the test. When specifying a docstring, we have<br>noticed that it is very difficult to identify the test later; therefore the method name is a much<br>better choice.<br>Line 8, 10, 14, . . . : The TestCase class implements a handful of methods that aid you with the<br>testing. Here are some of the most frequently used ones. For a complete list see the standard<br>Python documentation referenced above.<br>• assertEqual(first,second[,msg])<br>Checks whether the first and second value are equal. If the test fails, the msg or None<br>is returned.<br>• assertNotEqual(first,second[,msg])<br>This is simply the opposite to assertEqual() by checking for non-equality.<br>• assertRaises(exception,callable,...)<br>You expect the callable to raise exception when executed. After the callable you can<br>specify any amount of positional and keyword arguments for the callable. If you expect<br>a group of exceptions from the execution, you can make exception a tuple of possible<br>exceptions.<br>• assert (expr[,msg])<br>Assert checks whether the specified expression executes correctly. If not, the test fails and<br>msg or None is returned.<br>• failUnlessEqual()<br>This testing method is equivalent to assertEqual().<br>• failUnless(expr[,msg])<br>This method is equivalent to assert (expr[,msg]).<br>• failif()<br>This is the opposite to failUnless().<br>• fail([msg])<br>Fails the running test without any evaluation. This is commonly used when testing various<br>possible execution paths at once and you would like to signify a failure if an improper path<br>was taken.<br>Line 6–10: This method tests the title attribute of the Sample class. The first test should<br>be of course that the attribute exists and has the expected initial value (line 8). Then the title<br>attribute is changed and we check whether the value was really stored. This might seem like<br>overkill, but later you might change the title in a way that it uses properties instead. Then it<br>becomes very important to check whether this test still passes.<br>Line 12–16: First we simply check that getDescription() returns the correct default value.<br>Since we do not want to use other API calls like setDescription() we set a new value of the<br>description via the implementation-internal description attribute (line 15). This is okay! Unit<br>tests can make use of implementation-specific attributes and methods. Finally we just check that<br>the correct value is returned.<br><hr><A name=5></a>44.3. RUNNING THE TESTS<br>5<br>Line 18–25: On line 21–24 it is checked that both regular and unicode strings are set correctly.<br>In the last line of the test we make sure that no other type of objects can be set as a description<br>and that an error is raised.<br>28–31: This method returns a test suite that includes all test cases created in this module. It is<br>used by the Zope 3 test runner when it picks up all available tests. You would basically add the<br>line unittest.makeSuite(TestCaseClass) for each additional test case.<br>33–34: In order to make the test module runnable by itself, you can execute unittest.main()<br>when the module is run.<br>44.3<br>Running the Tests<br>You can run the test by simply calling pythontest sample.py from the directory you saved the<br>file in. Here is the result you should see:<br>.<br>--------------------------------------------------------------------<br>n 3 tests in 0.001s<br>The three dots represent the three tests that were run. If a test had failed, it would have been<br>reported pointing out the failing test and providing a small traceback.<br>When using the default Zope 3 test runner, tests will be picked up as long as they follow some<br>conventions.<br>• The tests must either be in a package or be a module called tests.<br>• If tests is a package, then all test modules inside must also have a name starting with test,<br>as it is the case with our name test sample.py.<br>• The test module must be somewhere in the Zope 3 source tree, since the test runner looks<br>only for files there.<br>In our case, you could simply create a tests package in ZOPE3/src (do not forget the<br>init .<br>py file). Then place the test sample.py file into this directory.<br>You you can use the test runner to run only the sample tests as follows from the Zope 3 root<br>directory:<br>python test.py -vp tests.test_sample<br>The -v option stands for verbose mode, so that detailed information about a test failure is<br>provided. The -p option enables a progress bar that tells you how many tests out of all have been<br>completed. There are many more options that can be specified. You can get a full list of them with<br>the option -h: pythontest.py-h.<br>The output of the call above is as follows:<br>nfiguration file found.<br>nning UNIT tests at level 1<br>nning UNIT tests from /opt/zope/Zope3<br>3/3 (100.0%): test_title (tests.test_sample.SampleTest)<br>--------------------------------------------------------------------<br>n 3 tests in 0.002s<br><hr><A name=6></a>6<br>CHAPTER 44. WRITING BASIC UNIT TESTS<br>nning FUNCTIONAL tests at level 1<br>nning FUNCTIONAL tests from /opt/zope/Zope3<br>--------------------------------------------------------------------<br>n 0 tests in 0.000s<br>Line 1: The test runner uses a configuration file for some setup. This allows developers to use<br>the test runner for other projects as well. This message simply tells us that the configuration file<br>was found.<br>Line 2–8: The unit tests are run. On line 4 you can see the progress bar.<br>Line 9–15: The functional tests are run, since the default test runner runs both types of tests.<br>Since we do not have any functional tests in the specified module, there are no tests to run. To<br>just run the unit tests, use option -u and -f for just running the functional tests. See “Writing<br>Functional Tests” for more detials on functional tests.<br><hr><A name=7></a>44.3. RUNNING THE TESTS<br>7<br>Exercises<br>1. It is not very common to do the setup – in our case sample=Sample() – in every test<br>method. Instead there exists a method called setUp() and its counterpart tearDown that<br>are run before and after each test, respectively. Change the test code above, so that it uses<br>the setUp() method. In later chapters and the rest of the book we will frequently use this<br>method of setting up tests.<br>2. Currently the test setDescription() test only verifies that None is not allowed as input<br>value.<br>(a) Improve the test, so that all other builtin types are tested as well.<br>(b) Also, make sure that any objects inheriting from str or unicode pass as valid values.<br><hr>]

IN pdf_to_html(/home/stefan/autotest/temp/python24-zope210-cmf21-plone33next/eggs/Products.PortalTransforms-1.6.6-py2.4.egg/Products/PortalTransforms/tests/input/demo1.pdf)



Failure in test testSameNoFilename (Products.PortalTransforms.tests.test_transforms.TransformTestSubclass)
Traceback (most recent call last):
  File "/home/stefan/autotest/temp/cache/Zope-2.10.11-final-py2.4/lib/python/Testing/ZopeTestCase/profiler.py", line 98, in __call__
    testMethod()
  File "/home/stefan/autotest/temp/python24-zope210-cmf21-plone33next/eggs/Products.PortalTransforms-1.6.6-py2.4.egg/Products/PortalTransforms/tests/test_transforms.py", line 73, in testSameNoFilename
    self.do_convert()
  File "/home/stefan/autotest/temp/python24-zope210-cmf21-plone33next/eggs/Products.PortalTransforms-1.6.6-py2.4.egg/Products/PortalTransforms/tests/test_transforms.py", line 58, in do_convert
    '[%s]\n\n!=\n\n[%s]\n\nIN %s(%s)' % (
  File "/usr/local/python2.4/lib/python2.4/unittest.py", line 333, in failUnlessEqual
    raise self.failureException, \
AssertionError: [<A name=1></a>Chapter&nbsp;44<br>Writing&nbsp;Basic&nbsp;Unit&nbsp;Tests<br>Difficulty<br>Newcomer<br>Skills<br>•&nbsp;All&nbsp;you&nbsp;need&nbsp;to&nbsp;know&nbsp;is&nbsp;some&nbsp;Python.<br>Problem/Task<br>As&nbsp;you&nbsp;know&nbsp;by&nbsp;now,&nbsp;Zope&nbsp;3&nbsp;gains&nbsp;its&nbsp;incredible&nbsp;stability&nbsp;from&nbsp;testing&nbsp;any&nbsp;code&nbsp;in&nbsp;great&nbsp;detail.&nbsp;The<br>currently&nbsp;most&nbsp;common&nbsp;method&nbsp;is&nbsp;to&nbsp;write&nbsp;unit&nbsp;tests.&nbsp;This&nbsp;chapter&nbsp;introduces&nbsp;unit&nbsp;tests&nbsp;–&nbsp;which<br>are&nbsp;Zope&nbsp;3&nbsp;independent&nbsp;–&nbsp;and&nbsp;introduces&nbsp;some&nbsp;of&nbsp;the&nbsp;subtleties.<br>Solution<br>44.1<br>Implementing&nbsp;the&nbsp;Sample&nbsp;Class<br>Before&nbsp;we&nbsp;can&nbsp;write&nbsp;tests,&nbsp;we&nbsp;have&nbsp;to&nbsp;write&nbsp;some&nbsp;code&nbsp;that&nbsp;we&nbsp;can&nbsp;test.&nbsp;Here,&nbsp;we&nbsp;will&nbsp;implement<br>a&nbsp;simple&nbsp;class&nbsp;called&nbsp;Sample&nbsp;with&nbsp;a&nbsp;public&nbsp;attribute&nbsp;title&nbsp;and&nbsp;description&nbsp;that&nbsp;is&nbsp;accessed<br>via&nbsp;getDescription()&nbsp;and&nbsp;mutated&nbsp;using&nbsp;setDescription().&nbsp;Further,&nbsp;the&nbsp;description&nbsp;must&nbsp;be<br>either&nbsp;a&nbsp;regular&nbsp;or&nbsp;unicode&nbsp;string.<br>Since&nbsp;this&nbsp;code&nbsp;will&nbsp;not&nbsp;depend&nbsp;on&nbsp;Zope,&nbsp;open&nbsp;a&nbsp;file&nbsp;named&nbsp;test&nbsp;sample.py&nbsp;anywhere&nbsp;and&nbsp;add<br>the&nbsp;following&nbsp;class:<br>1&nbsp;Sample(object):<br>2<br>&quot;&quot;&quot;A&nbsp;trivial&nbsp;Sample&nbsp;object.&quot;&quot;&quot;<br>3<br>4<br>title&nbsp;=&nbsp;None<br>5<br>6<br>def&nbsp;__init__(self):<br>7<br>&quot;&quot;&quot;Initialize&nbsp;object.&quot;&quot;&quot;<br>8<br>self._description&nbsp;=&nbsp;’’<br>9<br>1<br><hr><A name=2></a>2<br>CHAPTER&nbsp;44.&nbsp;WRITING&nbsp;BASIC&nbsp;UNIT&nbsp;TESTS<br>10<br>def&nbsp;setDescription(self,&nbsp;value):<br>11<br>&quot;&quot;&quot;Change&nbsp;the&nbsp;value&nbsp;of&nbsp;the&nbsp;description.&quot;&quot;&quot;<br>12<br>assert&nbsp;isinstance(value,&nbsp;(str,&nbsp;unicode))<br>13<br>self._description&nbsp;=&nbsp;value<br>14<br>15<br>def&nbsp;getDescription(self):<br>16<br>&quot;&quot;&quot;Change&nbsp;the&nbsp;value&nbsp;of&nbsp;the&nbsp;description.&quot;&quot;&quot;<br>17<br>return&nbsp;self._description<br>Line&nbsp;4:&nbsp;The&nbsp;title&nbsp;is&nbsp;just&nbsp;publicly&nbsp;declared&nbsp;and&nbsp;a&nbsp;value&nbsp;of&nbsp;None&nbsp;is&nbsp;given.&nbsp;Therefore&nbsp;this&nbsp;is&nbsp;just<br>a&nbsp;regular&nbsp;attribute.<br>Line&nbsp;8:&nbsp;The&nbsp;actual&nbsp;description&nbsp;string&nbsp;will&nbsp;be&nbsp;stored&nbsp;in&nbsp;description.<br>Line&nbsp;12:&nbsp;Make&nbsp;sure&nbsp;that&nbsp;the&nbsp;description&nbsp;is&nbsp;only&nbsp;a&nbsp;regular&nbsp;or&nbsp;unicode&nbsp;string,&nbsp;like&nbsp;it&nbsp;was&nbsp;stated&nbsp;in<br>the&nbsp;requirements.<br>If&nbsp;you&nbsp;wish&nbsp;you&nbsp;can&nbsp;now&nbsp;manually&nbsp;test&nbsp;the&nbsp;class&nbsp;with&nbsp;the&nbsp;interactive&nbsp;Python&nbsp;shell.&nbsp;Just&nbsp;start<br>Python&nbsp;by&nbsp;entering&nbsp;python&nbsp;in&nbsp;your&nbsp;shell&nbsp;prompt.&nbsp;Note&nbsp;that&nbsp;you&nbsp;should&nbsp;be&nbsp;in&nbsp;the&nbsp;directory&nbsp;in<br>which&nbsp;test&nbsp;sample.py&nbsp;is&nbsp;located&nbsp;when&nbsp;starting&nbsp;Python&nbsp;(an&nbsp;alternative&nbsp;is&nbsp;of&nbsp;course&nbsp;to&nbsp;specify&nbsp;the<br>directory&nbsp;in&nbsp;your&nbsp;PYTHONPATH.)<br>1&nbsp;&gt;&gt;&gt;&nbsp;from&nbsp;test_sample&nbsp;import&nbsp;Sample<br>2&nbsp;&gt;&gt;&gt;&nbsp;sample&nbsp;=&nbsp;Sample()<br>3&nbsp;&gt;&gt;&gt;&nbsp;print&nbsp;sample.title<br>4&nbsp;None<br>5&nbsp;&gt;&gt;&gt;&nbsp;sample.title&nbsp;=&nbsp;’Title’<br>6&nbsp;&gt;&gt;&gt;&nbsp;print&nbsp;sample.title<br>7&nbsp;Title<br>8&nbsp;&gt;&gt;&gt;&nbsp;print&nbsp;sample.getDescription()<br>9<br>10&nbsp;&gt;&gt;&gt;&nbsp;sample.setDescription(’Hello&nbsp;World’)<br>11&nbsp;&gt;&gt;&gt;&nbsp;print&nbsp;sample.getDescription()<br>12&nbsp;Hello&nbsp;World<br>13&nbsp;&gt;&gt;&gt;&nbsp;sample.setDescription(None)<br>14&nbsp;Traceback&nbsp;(most&nbsp;recent&nbsp;call&nbsp;last):<br>15<br>File&nbsp;&quot;&lt;stdin&gt;&quot;,&nbsp;line&nbsp;1,&nbsp;in&nbsp;?<br>16<br>File&nbsp;&quot;test_sample.py&quot;,&nbsp;line&nbsp;31,&nbsp;in&nbsp;setDescription<br>17<br>assert&nbsp;isinstance(value,&nbsp;(str,&nbsp;unicode))<br>18&nbsp;AssertionError<br>As&nbsp;you&nbsp;can&nbsp;see&nbsp;in&nbsp;the&nbsp;last&nbsp;test,&nbsp;non-string&nbsp;object&nbsp;types&nbsp;are&nbsp;not&nbsp;allowed&nbsp;as&nbsp;descriptions&nbsp;and&nbsp;an<br>AssertionError&nbsp;is&nbsp;raised.<br>44.2<br>Writing&nbsp;the&nbsp;Unit&nbsp;Tests<br>The&nbsp;goal&nbsp;of&nbsp;writing&nbsp;the&nbsp;unit&nbsp;tests&nbsp;is&nbsp;to&nbsp;convert&nbsp;this&nbsp;informal,&nbsp;manual,&nbsp;and&nbsp;interactive&nbsp;testing&nbsp;session<br>into&nbsp;a&nbsp;formal&nbsp;test&nbsp;class.&nbsp;Python&nbsp;provides&nbsp;already&nbsp;a&nbsp;module&nbsp;called&nbsp;unittest&nbsp;for&nbsp;this&nbsp;purpose,&nbsp;which<br>is&nbsp;a&nbsp;port&nbsp;of&nbsp;the&nbsp;Java-based&nbsp;unit&nbsp;testing&nbsp;product,&nbsp;JUnit,&nbsp;by&nbsp;Kent&nbsp;Beck&nbsp;and&nbsp;Erich&nbsp;Gamma.&nbsp;There&nbsp;are<br>three&nbsp;levels&nbsp;to&nbsp;the&nbsp;testing&nbsp;framework&nbsp;(this&nbsp;list&nbsp;deviates&nbsp;a&nbsp;bit&nbsp;from&nbsp;the&nbsp;original&nbsp;definitions&nbsp;as&nbsp;found<br>in&nbsp;the&nbsp;Python&nbsp;library&nbsp;documentation.&nbsp;1).<br>1&nbsp;http://www.python.org/doc/current/lib/module-unittest.html<br><hr><A name=3></a>44.2.&nbsp;WRITING&nbsp;THE&nbsp;UNIT&nbsp;TESTS<br>3<br>The&nbsp;smallest&nbsp;unit&nbsp;is&nbsp;obviously&nbsp;the&nbsp;“test”,&nbsp;which&nbsp;is&nbsp;a&nbsp;single&nbsp;method&nbsp;in&nbsp;a&nbsp;TestCase&nbsp;class&nbsp;that<br>tests&nbsp;the&nbsp;behavior&nbsp;of&nbsp;a&nbsp;small&nbsp;piece&nbsp;of&nbsp;code&nbsp;or&nbsp;a&nbsp;particular&nbsp;aspect&nbsp;of&nbsp;an&nbsp;implementation.&nbsp;The&nbsp;“test<br>case”&nbsp;is&nbsp;then&nbsp;a&nbsp;collection&nbsp;tests&nbsp;that&nbsp;share&nbsp;the&nbsp;same&nbsp;setup/inputs.&nbsp;On&nbsp;top&nbsp;of&nbsp;all&nbsp;of&nbsp;this&nbsp;sits&nbsp;the&nbsp;“test<br>suite”&nbsp;which&nbsp;is&nbsp;a&nbsp;collection&nbsp;of&nbsp;test&nbsp;cases&nbsp;and/or&nbsp;other&nbsp;test&nbsp;suites.&nbsp;Test&nbsp;suites&nbsp;combine&nbsp;tests&nbsp;that<br>should&nbsp;be&nbsp;executed&nbsp;together.&nbsp;With&nbsp;the&nbsp;correct&nbsp;setup&nbsp;(as&nbsp;shown&nbsp;in&nbsp;the&nbsp;example&nbsp;below),&nbsp;you&nbsp;can<br>then&nbsp;execute&nbsp;test&nbsp;suites.&nbsp;For&nbsp;large&nbsp;projects&nbsp;like&nbsp;Zope&nbsp;3,&nbsp;it&nbsp;is&nbsp;useful&nbsp;to&nbsp;know&nbsp;that&nbsp;there&nbsp;is&nbsp;also&nbsp;the<br>concept&nbsp;of&nbsp;a&nbsp;test&nbsp;runner,&nbsp;which&nbsp;manages&nbsp;the&nbsp;test&nbsp;run&nbsp;of&nbsp;all&nbsp;or&nbsp;a&nbsp;set&nbsp;of&nbsp;tests.&nbsp;The&nbsp;runner&nbsp;provides<br>useful&nbsp;feedback&nbsp;to&nbsp;the&nbsp;application,&nbsp;so&nbsp;that&nbsp;various&nbsp;user&nbsp;interaces&nbsp;can&nbsp;be&nbsp;developed&nbsp;on&nbsp;top&nbsp;of&nbsp;it.<br>But&nbsp;enough&nbsp;about&nbsp;the&nbsp;theory.&nbsp;In&nbsp;the&nbsp;following&nbsp;example,&nbsp;which&nbsp;you&nbsp;can&nbsp;simply&nbsp;put&nbsp;into&nbsp;the&nbsp;same<br>file&nbsp;as&nbsp;your&nbsp;code&nbsp;above,&nbsp;you&nbsp;will&nbsp;see&nbsp;a&nbsp;test&nbsp;in&nbsp;common&nbsp;Zope&nbsp;3&nbsp;style.<br>1&nbsp;import&nbsp;unittest<br>2<br>3&nbsp;class&nbsp;SampleTest(unittest.TestCase):<br>4<br>&quot;&quot;&quot;Test&nbsp;the&nbsp;Sample&nbsp;class&quot;&quot;&quot;<br>5<br>6<br>def&nbsp;test_title(self):<br>7<br>sample&nbsp;=&nbsp;Sample()<br>8<br>self.assertEqual(sample.title,&nbsp;None)<br>9<br>sample.title&nbsp;=&nbsp;’Sample&nbsp;Title’<br>10<br>self.assertEqual(sample.title,&nbsp;’Sample&nbsp;Title’)<br>11<br>12<br>def&nbsp;test_getDescription(self):<br>13<br>sample&nbsp;=&nbsp;Sample()<br>14<br>self.assertEqual(sample.getDescription(),&nbsp;’’)<br>15<br>sample._description&nbsp;=&nbsp;&quot;Description&quot;<br>16<br>self.assertEqual(sample.getDescription(),&nbsp;’Description’)<br>17<br>18<br>def&nbsp;test_setDescription(self):<br>19<br>sample&nbsp;=&nbsp;Sample()<br>20<br>self.assertEqual(sample._description,&nbsp;’’)<br>21<br>sample.setDescription(’Description’)<br>22<br>self.assertEqual(sample._description,&nbsp;’Description’)<br>23<br>sample.setDescription(u’Description2’)<br>24<br>self.assertEqual(sample._description,&nbsp;u’Description2’)<br>25<br>self.assertRaises(AssertionError,&nbsp;sample.setDescription,&nbsp;None)<br>26<br>27<br>28&nbsp;def&nbsp;test_suite():<br>29<br>return&nbsp;unittest.TestSuite((<br>30<br>unittest.makeSuite(SampleTest),<br>31<br>))<br>32<br>33&nbsp;if&nbsp;__name__&nbsp;==&nbsp;’__main__’:<br>34<br>unittest.main(defaultTest=’test_suite’)<br>Line&nbsp;3–4:&nbsp;We&nbsp;usually&nbsp;develop&nbsp;test&nbsp;classes&nbsp;which&nbsp;must&nbsp;inherit&nbsp;from&nbsp;TestCase.&nbsp;While&nbsp;often&nbsp;not<br>done,&nbsp;it&nbsp;is&nbsp;a&nbsp;good&nbsp;idea&nbsp;to&nbsp;give&nbsp;the&nbsp;class&nbsp;a&nbsp;meaningful&nbsp;docstring&nbsp;that&nbsp;describes&nbsp;the&nbsp;purpose&nbsp;of&nbsp;the<br>tests&nbsp;it&nbsp;includes.<br>Line&nbsp;6,&nbsp;12&nbsp;&amp;&nbsp;18:&nbsp;When&nbsp;a&nbsp;test&nbsp;case&nbsp;is&nbsp;run,&nbsp;a&nbsp;method&nbsp;called&nbsp;runTests()&nbsp;is&nbsp;executed.&nbsp;While&nbsp;it<br>is&nbsp;possible&nbsp;to&nbsp;overrride&nbsp;this&nbsp;method&nbsp;to&nbsp;run&nbsp;tests&nbsp;differently,&nbsp;the&nbsp;default&nbsp;option&nbsp;will&nbsp;look&nbsp;for&nbsp;any<br>method&nbsp;whose&nbsp;name&nbsp;starts&nbsp;with&nbsp;test&nbsp;and&nbsp;execute&nbsp;it&nbsp;as&nbsp;a&nbsp;single&nbsp;test.&nbsp;This&nbsp;way&nbsp;we&nbsp;can&nbsp;create<br>a&nbsp;“test&nbsp;method”&nbsp;for&nbsp;each&nbsp;aspect,&nbsp;method,&nbsp;function&nbsp;or&nbsp;property&nbsp;of&nbsp;the&nbsp;code&nbsp;to&nbsp;be&nbsp;tested.&nbsp;This<br>default&nbsp;is&nbsp;very&nbsp;sensible&nbsp;and&nbsp;is&nbsp;used&nbsp;everywhere&nbsp;in&nbsp;Zope&nbsp;3.<br><hr><A name=4></a>4<br>CHAPTER&nbsp;44.&nbsp;WRITING&nbsp;BASIC&nbsp;UNIT&nbsp;TESTS<br>Note&nbsp;that&nbsp;there&nbsp;is&nbsp;no&nbsp;docstring&nbsp;for&nbsp;test&nbsp;methods.&nbsp;This&nbsp;is&nbsp;intentional.&nbsp;If&nbsp;a&nbsp;docstring&nbsp;is&nbsp;specified,<br>it&nbsp;is&nbsp;used&nbsp;instead&nbsp;of&nbsp;the&nbsp;method&nbsp;name&nbsp;to&nbsp;identify&nbsp;the&nbsp;test.&nbsp;When&nbsp;specifying&nbsp;a&nbsp;docstring,&nbsp;we&nbsp;have<br>noticed&nbsp;that&nbsp;it&nbsp;is&nbsp;very&nbsp;difficult&nbsp;to&nbsp;identify&nbsp;the&nbsp;test&nbsp;later;&nbsp;therefore&nbsp;the&nbsp;method&nbsp;name&nbsp;is&nbsp;a&nbsp;much<br>better&nbsp;choice.<br>Line&nbsp;8,&nbsp;10,&nbsp;14,&nbsp;.&nbsp;.&nbsp;.&nbsp;:&nbsp;The&nbsp;TestCase&nbsp;class&nbsp;implements&nbsp;a&nbsp;handful&nbsp;of&nbsp;methods&nbsp;that&nbsp;aid&nbsp;you&nbsp;with&nbsp;the<br>testing.&nbsp;Here&nbsp;are&nbsp;some&nbsp;of&nbsp;the&nbsp;most&nbsp;frequently&nbsp;used&nbsp;ones.&nbsp;For&nbsp;a&nbsp;complete&nbsp;list&nbsp;see&nbsp;the&nbsp;standard<br>Python&nbsp;documentation&nbsp;referenced&nbsp;above.<br>•&nbsp;assertEqual(first,second[,msg])<br>Checks&nbsp;whether&nbsp;the&nbsp;first&nbsp;and&nbsp;second&nbsp;value&nbsp;are&nbsp;equal.&nbsp;If&nbsp;the&nbsp;test&nbsp;fails,&nbsp;the&nbsp;msg&nbsp;or&nbsp;None<br>is&nbsp;returned.<br>•&nbsp;assertNotEqual(first,second[,msg])<br>This&nbsp;is&nbsp;simply&nbsp;the&nbsp;opposite&nbsp;to&nbsp;assertEqual()&nbsp;by&nbsp;checking&nbsp;for&nbsp;non-equality.<br>•&nbsp;assertRaises(exception,callable,...)<br>You&nbsp;expect&nbsp;the&nbsp;callable&nbsp;to&nbsp;raise&nbsp;exception&nbsp;when&nbsp;executed.&nbsp;After&nbsp;the&nbsp;callable&nbsp;you&nbsp;can<br>specify&nbsp;any&nbsp;amount&nbsp;of&nbsp;positional&nbsp;and&nbsp;keyword&nbsp;arguments&nbsp;for&nbsp;the&nbsp;callable.&nbsp;If&nbsp;you&nbsp;expect<br>a&nbsp;group&nbsp;of&nbsp;exceptions&nbsp;from&nbsp;the&nbsp;execution,&nbsp;you&nbsp;can&nbsp;make&nbsp;exception&nbsp;a&nbsp;tuple&nbsp;of&nbsp;possible<br>exceptions.<br>•&nbsp;assert&nbsp;(expr[,msg])<br>Assert&nbsp;checks&nbsp;whether&nbsp;the&nbsp;specified&nbsp;expression&nbsp;executes&nbsp;correctly.&nbsp;If&nbsp;not,&nbsp;the&nbsp;test&nbsp;fails&nbsp;and<br>msg&nbsp;or&nbsp;None&nbsp;is&nbsp;returned.<br>•&nbsp;failUnlessEqual()<br>This&nbsp;testing&nbsp;method&nbsp;is&nbsp;equivalent&nbsp;to&nbsp;assertEqual().<br>•&nbsp;failUnless(expr[,msg])<br>This&nbsp;method&nbsp;is&nbsp;equivalent&nbsp;to&nbsp;assert&nbsp;(expr[,msg]).<br>•&nbsp;failif()<br>This&nbsp;is&nbsp;the&nbsp;opposite&nbsp;to&nbsp;failUnless().<br>•&nbsp;fail([msg])<br>Fails&nbsp;the&nbsp;running&nbsp;test&nbsp;without&nbsp;any&nbsp;evaluation.&nbsp;This&nbsp;is&nbsp;commonly&nbsp;used&nbsp;when&nbsp;testing&nbsp;various<br>possible&nbsp;execution&nbsp;paths&nbsp;at&nbsp;once&nbsp;and&nbsp;you&nbsp;would&nbsp;like&nbsp;to&nbsp;signify&nbsp;a&nbsp;failure&nbsp;if&nbsp;an&nbsp;improper&nbsp;path<br>was&nbsp;taken.<br>Line&nbsp;6–10:&nbsp;This&nbsp;method&nbsp;tests&nbsp;the&nbsp;title&nbsp;attribute&nbsp;of&nbsp;the&nbsp;Sample&nbsp;class.&nbsp;The&nbsp;first&nbsp;test&nbsp;should<br>be&nbsp;of&nbsp;course&nbsp;that&nbsp;the&nbsp;attribute&nbsp;exists&nbsp;and&nbsp;has&nbsp;the&nbsp;expected&nbsp;initial&nbsp;value&nbsp;(line&nbsp;8).&nbsp;Then&nbsp;the&nbsp;title<br>attribute&nbsp;is&nbsp;changed&nbsp;and&nbsp;we&nbsp;check&nbsp;whether&nbsp;the&nbsp;value&nbsp;was&nbsp;really&nbsp;stored.&nbsp;This&nbsp;might&nbsp;seem&nbsp;like<br>overkill,&nbsp;but&nbsp;later&nbsp;you&nbsp;might&nbsp;change&nbsp;the&nbsp;title&nbsp;in&nbsp;a&nbsp;way&nbsp;that&nbsp;it&nbsp;uses&nbsp;properties&nbsp;instead.&nbsp;Then&nbsp;it<br>becomes&nbsp;very&nbsp;important&nbsp;to&nbsp;check&nbsp;whether&nbsp;this&nbsp;test&nbsp;still&nbsp;passes.<br>Line&nbsp;12–16:&nbsp;First&nbsp;we&nbsp;simply&nbsp;check&nbsp;that&nbsp;getDescription()&nbsp;returns&nbsp;the&nbsp;correct&nbsp;default&nbsp;value.<br>Since&nbsp;we&nbsp;do&nbsp;not&nbsp;want&nbsp;to&nbsp;use&nbsp;other&nbsp;API&nbsp;calls&nbsp;like&nbsp;setDescription()&nbsp;we&nbsp;set&nbsp;a&nbsp;new&nbsp;value&nbsp;of&nbsp;the<br>description&nbsp;via&nbsp;the&nbsp;implementation-internal&nbsp;description&nbsp;attribute&nbsp;(line&nbsp;15).&nbsp;This&nbsp;is&nbsp;okay!&nbsp;Unit<br>tests&nbsp;can&nbsp;make&nbsp;use&nbsp;of&nbsp;implementation-specific&nbsp;attributes&nbsp;and&nbsp;methods.&nbsp;Finally&nbsp;we&nbsp;just&nbsp;check&nbsp;that<br>the&nbsp;correct&nbsp;value&nbsp;is&nbsp;returned.<br><hr><A name=5></a>44.3.&nbsp;RUNNING&nbsp;THE&nbsp;TESTS<br>5<br>Line&nbsp;18–25:&nbsp;On&nbsp;line&nbsp;21–24&nbsp;it&nbsp;is&nbsp;checked&nbsp;that&nbsp;both&nbsp;regular&nbsp;and&nbsp;unicode&nbsp;strings&nbsp;are&nbsp;set&nbsp;correctly.<br>In&nbsp;the&nbsp;last&nbsp;line&nbsp;of&nbsp;the&nbsp;test&nbsp;we&nbsp;make&nbsp;sure&nbsp;that&nbsp;no&nbsp;other&nbsp;type&nbsp;of&nbsp;objects&nbsp;can&nbsp;be&nbsp;set&nbsp;as&nbsp;a&nbsp;description<br>and&nbsp;that&nbsp;an&nbsp;error&nbsp;is&nbsp;raised.<br>28–31:&nbsp;This&nbsp;method&nbsp;returns&nbsp;a&nbsp;test&nbsp;suite&nbsp;that&nbsp;includes&nbsp;all&nbsp;test&nbsp;cases&nbsp;created&nbsp;in&nbsp;this&nbsp;module.&nbsp;It&nbsp;is<br>used&nbsp;by&nbsp;the&nbsp;Zope&nbsp;3&nbsp;test&nbsp;runner&nbsp;when&nbsp;it&nbsp;picks&nbsp;up&nbsp;all&nbsp;available&nbsp;tests.&nbsp;You&nbsp;would&nbsp;basically&nbsp;add&nbsp;the<br>line&nbsp;unittest.makeSuite(TestCaseClass)&nbsp;for&nbsp;each&nbsp;additional&nbsp;test&nbsp;case.<br>33–34:&nbsp;In&nbsp;order&nbsp;to&nbsp;make&nbsp;the&nbsp;test&nbsp;module&nbsp;runnable&nbsp;by&nbsp;itself,&nbsp;you&nbsp;can&nbsp;execute&nbsp;unittest.main()<br>when&nbsp;the&nbsp;module&nbsp;is&nbsp;run.<br>44.3<br>Running&nbsp;the&nbsp;Tests<br>You&nbsp;can&nbsp;run&nbsp;the&nbsp;test&nbsp;by&nbsp;simply&nbsp;calling&nbsp;pythontest&nbsp;sample.py&nbsp;from&nbsp;the&nbsp;directory&nbsp;you&nbsp;saved&nbsp;the<br>file&nbsp;in.&nbsp;Here&nbsp;is&nbsp;the&nbsp;result&nbsp;you&nbsp;should&nbsp;see:<br>.<br>--------------------------------------------------------------------<br>n&nbsp;3&nbsp;tests&nbsp;in&nbsp;0.001s<br>The&nbsp;three&nbsp;dots&nbsp;represent&nbsp;the&nbsp;three&nbsp;tests&nbsp;that&nbsp;were&nbsp;run.&nbsp;If&nbsp;a&nbsp;test&nbsp;had&nbsp;failed,&nbsp;it&nbsp;would&nbsp;have&nbsp;been<br>reported&nbsp;pointing&nbsp;out&nbsp;the&nbsp;failing&nbsp;test&nbsp;and&nbsp;providing&nbsp;a&nbsp;small&nbsp;traceback.<br>When&nbsp;using&nbsp;the&nbsp;default&nbsp;Zope&nbsp;3&nbsp;test&nbsp;runner,&nbsp;tests&nbsp;will&nbsp;be&nbsp;picked&nbsp;up&nbsp;as&nbsp;long&nbsp;as&nbsp;they&nbsp;follow&nbsp;some<br>conventions.<br>•&nbsp;The&nbsp;tests&nbsp;must&nbsp;either&nbsp;be&nbsp;in&nbsp;a&nbsp;package&nbsp;or&nbsp;be&nbsp;a&nbsp;module&nbsp;called&nbsp;tests.<br>•&nbsp;If&nbsp;tests&nbsp;is&nbsp;a&nbsp;package,&nbsp;then&nbsp;all&nbsp;test&nbsp;modules&nbsp;inside&nbsp;must&nbsp;also&nbsp;have&nbsp;a&nbsp;name&nbsp;starting&nbsp;with&nbsp;test,<br>as&nbsp;it&nbsp;is&nbsp;the&nbsp;case&nbsp;with&nbsp;our&nbsp;name&nbsp;test&nbsp;sample.py.<br>•&nbsp;The&nbsp;test&nbsp;module&nbsp;must&nbsp;be&nbsp;somewhere&nbsp;in&nbsp;the&nbsp;Zope&nbsp;3&nbsp;source&nbsp;tree,&nbsp;since&nbsp;the&nbsp;test&nbsp;runner&nbsp;looks<br>only&nbsp;for&nbsp;files&nbsp;there.<br>In&nbsp;our&nbsp;case,&nbsp;you&nbsp;could&nbsp;simply&nbsp;create&nbsp;a&nbsp;tests&nbsp;package&nbsp;in&nbsp;ZOPE3/src&nbsp;(do&nbsp;not&nbsp;forget&nbsp;the<br>init&nbsp;.<br>py&nbsp;file).&nbsp;Then&nbsp;place&nbsp;the&nbsp;test&nbsp;sample.py&nbsp;file&nbsp;into&nbsp;this&nbsp;directory.<br>You&nbsp;you&nbsp;can&nbsp;use&nbsp;the&nbsp;test&nbsp;runner&nbsp;to&nbsp;run&nbsp;only&nbsp;the&nbsp;sample&nbsp;tests&nbsp;as&nbsp;follows&nbsp;from&nbsp;the&nbsp;Zope&nbsp;3&nbsp;root<br>directory:<br>python&nbsp;test.py&nbsp;-vp&nbsp;tests.test_sample<br>The&nbsp;-v&nbsp;option&nbsp;stands&nbsp;for&nbsp;verbose&nbsp;mode,&nbsp;so&nbsp;that&nbsp;detailed&nbsp;information&nbsp;about&nbsp;a&nbsp;test&nbsp;failure&nbsp;is<br>provided.&nbsp;The&nbsp;-p&nbsp;option&nbsp;enables&nbsp;a&nbsp;progress&nbsp;bar&nbsp;that&nbsp;tells&nbsp;you&nbsp;how&nbsp;many&nbsp;tests&nbsp;out&nbsp;of&nbsp;all&nbsp;have&nbsp;been<br>completed.&nbsp;There&nbsp;are&nbsp;many&nbsp;more&nbsp;options&nbsp;that&nbsp;can&nbsp;be&nbsp;specified.&nbsp;You&nbsp;can&nbsp;get&nbsp;a&nbsp;full&nbsp;list&nbsp;of&nbsp;them&nbsp;with<br>the&nbsp;option&nbsp;-h:&nbsp;pythontest.py-h.<br>The&nbsp;output&nbsp;of&nbsp;the&nbsp;call&nbsp;above&nbsp;is&nbsp;as&nbsp;follows:<br>nfiguration&nbsp;file&nbsp;found.<br>nning&nbsp;UNIT&nbsp;tests&nbsp;at&nbsp;level&nbsp;1<br>nning&nbsp;UNIT&nbsp;tests&nbsp;from&nbsp;/opt/zope/Zope3<br>3/3&nbsp;(100.0%):&nbsp;test_title&nbsp;(tests.test_sample.SampleTest)<br>--------------------------------------------------------------------<br>n&nbsp;3&nbsp;tests&nbsp;in&nbsp;0.002s<br><hr><A name=6></a>6<br>CHAPTER&nbsp;44.&nbsp;WRITING&nbsp;BASIC&nbsp;UNIT&nbsp;TESTS<br>nning&nbsp;FUNCTIONAL&nbsp;tests&nbsp;at&nbsp;level&nbsp;1<br>nning&nbsp;FUNCTIONAL&nbsp;tests&nbsp;from&nbsp;/opt/zope/Zope3<br>--------------------------------------------------------------------<br>n&nbsp;0&nbsp;tests&nbsp;in&nbsp;0.000s<br>Line&nbsp;1:&nbsp;The&nbsp;test&nbsp;runner&nbsp;uses&nbsp;a&nbsp;configuration&nbsp;file&nbsp;for&nbsp;some&nbsp;setup.&nbsp;This&nbsp;allows&nbsp;developers&nbsp;to&nbsp;use<br>the&nbsp;test&nbsp;runner&nbsp;for&nbsp;other&nbsp;projects&nbsp;as&nbsp;well.&nbsp;This&nbsp;message&nbsp;simply&nbsp;tells&nbsp;us&nbsp;that&nbsp;the&nbsp;configuration&nbsp;file<br>was&nbsp;found.<br>Line&nbsp;2–8:&nbsp;The&nbsp;unit&nbsp;tests&nbsp;are&nbsp;run.&nbsp;On&nbsp;line&nbsp;4&nbsp;you&nbsp;can&nbsp;see&nbsp;the&nbsp;progress&nbsp;bar.<br>Line&nbsp;9–15:&nbsp;The&nbsp;functional&nbsp;tests&nbsp;are&nbsp;run,&nbsp;since&nbsp;the&nbsp;default&nbsp;test&nbsp;runner&nbsp;runs&nbsp;both&nbsp;types&nbsp;of&nbsp;tests.<br>Since&nbsp;we&nbsp;do&nbsp;not&nbsp;have&nbsp;any&nbsp;functional&nbsp;tests&nbsp;in&nbsp;the&nbsp;specified&nbsp;module,&nbsp;there&nbsp;are&nbsp;no&nbsp;tests&nbsp;to&nbsp;run.&nbsp;To<br>just&nbsp;run&nbsp;the&nbsp;unit&nbsp;tests,&nbsp;use&nbsp;option&nbsp;-u&nbsp;and&nbsp;-f&nbsp;for&nbsp;just&nbsp;running&nbsp;the&nbsp;functional&nbsp;tests.&nbsp;See&nbsp;“Writing<br>Functional&nbsp;Tests”&nbsp;for&nbsp;more&nbsp;detials&nbsp;on&nbsp;functional&nbsp;tests.<br><hr><A name=7></a>44.3.&nbsp;RUNNING&nbsp;THE&nbsp;TESTS<br>7<br>Exercises<br>1.&nbsp;It&nbsp;is&nbsp;not&nbsp;very&nbsp;common&nbsp;to&nbsp;do&nbsp;the&nbsp;setup&nbsp;–&nbsp;in&nbsp;our&nbsp;case&nbsp;sample=Sample()&nbsp;–&nbsp;in&nbsp;every&nbsp;test<br>method.&nbsp;Instead&nbsp;there&nbsp;exists&nbsp;a&nbsp;method&nbsp;called&nbsp;setUp()&nbsp;and&nbsp;its&nbsp;counterpart&nbsp;tearDown&nbsp;that<br>are&nbsp;run&nbsp;before&nbsp;and&nbsp;after&nbsp;each&nbsp;test,&nbsp;respectively.&nbsp;Change&nbsp;the&nbsp;test&nbsp;code&nbsp;above,&nbsp;so&nbsp;that&nbsp;it&nbsp;uses<br>the&nbsp;setUp()&nbsp;method.&nbsp;In&nbsp;later&nbsp;chapters&nbsp;and&nbsp;the&nbsp;rest&nbsp;of&nbsp;the&nbsp;book&nbsp;we&nbsp;will&nbsp;frequently&nbsp;use&nbsp;this<br>method&nbsp;of&nbsp;setting&nbsp;up&nbsp;tests.<br>2.&nbsp;Currently&nbsp;the&nbsp;test&nbsp;setDescription()&nbsp;test&nbsp;only&nbsp;verifies&nbsp;that&nbsp;None&nbsp;is&nbsp;not&nbsp;allowed&nbsp;as&nbsp;input<br>value.<br>(a)&nbsp;Improve&nbsp;the&nbsp;test,&nbsp;so&nbsp;that&nbsp;all&nbsp;other&nbsp;builtin&nbsp;types&nbsp;are&nbsp;tested&nbsp;as&nbsp;well.<br>(b)&nbsp;Also,&nbsp;make&nbsp;sure&nbsp;that&nbsp;any&nbsp;objects&nbsp;inheriting&nbsp;from&nbsp;str&nbsp;or&nbsp;unicode&nbsp;pass&nbsp;as&nbsp;valid&nbsp;values.<br><hr>]

!=

[<A name=1></a>Chapter 44<br>Writing Basic Unit Tests<br>Difficulty<br>Newcomer<br>Skills<br>• All you need to know is some Python.<br>Problem/Task<br>As you know by now, Zope 3 gains its incredible stability from testing any code in great detail. The<br>currently most common method is to write unit tests. This chapter introduces unit tests – which<br>are Zope 3 independent – and introduces some of the subtleties.<br>Solution<br>44.1<br>Implementing the Sample Class<br>Before we can write tests, we have to write some code that we can test. Here, we will implement<br>a simple class called Sample with a public attribute title and description that is accessed<br>via getDescription() and mutated using setDescription(). Further, the description must be<br>either a regular or unicode string.<br>Since this code will not depend on Zope, open a file named test sample.py anywhere and add<br>the following class:<br>1 Sample(object):<br>2<br>&quot;&quot;&quot;A trivial Sample object.&quot;&quot;&quot;<br>3<br>4<br>title = None<br>5<br>6<br>def __init__(self):<br>7<br>&quot;&quot;&quot;Initialize object.&quot;&quot;&quot;<br>8<br>self._description = ’’<br>9<br>1<br><hr><A name=2></a>2<br>CHAPTER 44. WRITING BASIC UNIT TESTS<br>10<br>def setDescription(self, value):<br>11<br>&quot;&quot;&quot;Change the value of the description.&quot;&quot;&quot;<br>12<br>assert isinstance(value, (str, unicode))<br>13<br>self._description = value<br>14<br>15<br>def getDescription(self):<br>16<br>&quot;&quot;&quot;Change the value of the description.&quot;&quot;&quot;<br>17<br>return self._description<br>Line 4: The title is just publicly declared and a value of None is given. Therefore this is just<br>a regular attribute.<br>Line 8: The actual description string will be stored in description.<br>Line 12: Make sure that the description is only a regular or unicode string, like it was stated in<br>the requirements.<br>If you wish you can now manually test the class with the interactive Python shell. Just start<br>Python by entering python in your shell prompt. Note that you should be in the directory in<br>which test sample.py is located when starting Python (an alternative is of course to specify the<br>directory in your PYTHONPATH.)<br>1 &gt;&gt;&gt; from test_sample import Sample<br>2 &gt;&gt;&gt; sample = Sample()<br>3 &gt;&gt;&gt; print sample.title<br>4 None<br>5 &gt;&gt;&gt; sample.title = ’Title’<br>6 &gt;&gt;&gt; print sample.title<br>7 Title<br>8 &gt;&gt;&gt; print sample.getDescription()<br>9<br>10 &gt;&gt;&gt; sample.setDescription(’Hello World’)<br>11 &gt;&gt;&gt; print sample.getDescription()<br>12 Hello World<br>13 &gt;&gt;&gt; sample.setDescription(None)<br>14 Traceback (most recent call last):<br>15<br>File &quot;&lt;stdin&gt;&quot;, line 1, in ?<br>16<br>File &quot;test_sample.py&quot;, line 31, in setDescription<br>17<br>assert isinstance(value, (str, unicode))<br>18 AssertionError<br>As you can see in the last test, non-string object types are not allowed as descriptions and an<br>AssertionError is raised.<br>44.2<br>Writing the Unit Tests<br>The goal of writing the unit tests is to convert this informal, manual, and interactive testing session<br>into a formal test class. Python provides already a module called unittest for this purpose, which<br>is a port of the Java-based unit testing product, JUnit, by Kent Beck and Erich Gamma. There are<br>three levels to the testing framework (this list deviates a bit from the original definitions as found<br>in the Python library documentation. 1).<br>1 http://www.python.org/doc/current/lib/module-unittest.html<br><hr><A name=3></a>44.2. WRITING THE UNIT TESTS<br>3<br>The smallest unit is obviously the “test”, which is a single method in a TestCase class that<br>tests the behavior of a small piece of code or a particular aspect of an implementation. The “test<br>case” is then a collection tests that share the same setup/inputs. On top of all of this sits the “test<br>suite” which is a collection of test cases and/or other test suites. Test suites combine tests that<br>should be executed together. With the correct setup (as shown in the example below), you can<br>then execute test suites. For large projects like Zope 3, it is useful to know that there is also the<br>concept of a test runner, which manages the test run of all or a set of tests. The runner provides<br>useful feedback to the application, so that various user interaces can be developed on top of it.<br>But enough about the theory. In the following example, which you can simply put into the same<br>file as your code above, you will see a test in common Zope 3 style.<br>1 import unittest<br>2<br>3 class SampleTest(unittest.TestCase):<br>4<br>&quot;&quot;&quot;Test the Sample class&quot;&quot;&quot;<br>5<br>6<br>def test_title(self):<br>7<br>sample = Sample()<br>8<br>self.assertEqual(sample.title, None)<br>9<br>sample.title = ’Sample Title’<br>10<br>self.assertEqual(sample.title, ’Sample Title’)<br>11<br>12<br>def test_getDescription(self):<br>13<br>sample = Sample()<br>14<br>self.assertEqual(sample.getDescription(), ’’)<br>15<br>sample._description = &quot;Description&quot;<br>16<br>self.assertEqual(sample.getDescription(), ’Description’)<br>17<br>18<br>def test_setDescription(self):<br>19<br>sample = Sample()<br>20<br>self.assertEqual(sample._description, ’’)<br>21<br>sample.setDescription(’Description’)<br>22<br>self.assertEqual(sample._description, ’Description’)<br>23<br>sample.setDescription(u’Description2’)<br>24<br>self.assertEqual(sample._description, u’Description2’)<br>25<br>self.assertRaises(AssertionError, sample.setDescription, None)<br>26<br>27<br>28 def test_suite():<br>29<br>return unittest.TestSuite((<br>30<br>unittest.makeSuite(SampleTest),<br>31<br>))<br>32<br>33 if __name__ == ’__main__’:<br>34<br>unittest.main(defaultTest=’test_suite’)<br>Line 3–4: We usually develop test classes which must inherit from TestCase. While often not<br>done, it is a good idea to give the class a meaningful docstring that describes the purpose of the<br>tests it includes.<br>Line 6, 12 &amp; 18: When a test case is run, a method called runTests() is executed. While it<br>is possible to overrride this method to run tests differently, the default option will look for any<br>method whose name starts with test and execute it as a single test. This way we can create<br>a “test method” for each aspect, method, function or property of the code to be tested. This<br>default is very sensible and is used everywhere in Zope 3.<br><hr><A name=4></a>4<br>CHAPTER 44. WRITING BASIC UNIT TESTS<br>Note that there is no docstring for test methods. This is intentional. If a docstring is specified,<br>it is used instead of the method name to identify the test. When specifying a docstring, we have<br>noticed that it is very difficult to identify the test later; therefore the method name is a much<br>better choice.<br>Line 8, 10, 14, . . . : The TestCase class implements a handful of methods that aid you with the<br>testing. Here are some of the most frequently used ones. For a complete list see the standard<br>Python documentation referenced above.<br>• assertEqual(first,second[,msg])<br>Checks whether the first and second value are equal. If the test fails, the msg or None<br>is returned.<br>• assertNotEqual(first,second[,msg])<br>This is simply the opposite to assertEqual() by checking for non-equality.<br>• assertRaises(exception,callable,...)<br>You expect the callable to raise exception when executed. After the callable you can<br>specify any amount of positional and keyword arguments for the callable. If you expect<br>a group of exceptions from the execution, you can make exception a tuple of possible<br>exceptions.<br>• assert (expr[,msg])<br>Assert checks whether the specified expression executes correctly. If not, the test fails and<br>msg or None is returned.<br>• failUnlessEqual()<br>This testing method is equivalent to assertEqual().<br>• failUnless(expr[,msg])<br>This method is equivalent to assert (expr[,msg]).<br>• failif()<br>This is the opposite to failUnless().<br>• fail([msg])<br>Fails the running test without any evaluation. This is commonly used when testing various<br>possible execution paths at once and you would like to signify a failure if an improper path<br>was taken.<br>Line 6–10: This method tests the title attribute of the Sample class. The first test should<br>be of course that the attribute exists and has the expected initial value (line 8). Then the title<br>attribute is changed and we check whether the value was really stored. This might seem like<br>overkill, but later you might change the title in a way that it uses properties instead. Then it<br>becomes very important to check whether this test still passes.<br>Line 12–16: First we simply check that getDescription() returns the correct default value.<br>Since we do not want to use other API calls like setDescription() we set a new value of the<br>description via the implementation-internal description attribute (line 15). This is okay! Unit<br>tests can make use of implementation-specific attributes and methods. Finally we just check that<br>the correct value is returned.<br><hr><A name=5></a>44.3. RUNNING THE TESTS<br>5<br>Line 18–25: On line 21–24 it is checked that both regular and unicode strings are set correctly.<br>In the last line of the test we make sure that no other type of objects can be set as a description<br>and that an error is raised.<br>28–31: This method returns a test suite that includes all test cases created in this module. It is<br>used by the Zope 3 test runner when it picks up all available tests. You would basically add the<br>line unittest.makeSuite(TestCaseClass) for each additional test case.<br>33–34: In order to make the test module runnable by itself, you can execute unittest.main()<br>when the module is run.<br>44.3<br>Running the Tests<br>You can run the test by simply calling pythontest sample.py from the directory you saved the<br>file in. Here is the result you should see:<br>.<br>--------------------------------------------------------------------<br>n 3 tests in 0.001s<br>The three dots represent the three tests that were run. If a test had failed, it would have been<br>reported pointing out the failing test and providing a small traceback.<br>When using the default Zope 3 test runner, tests will be picked up as long as they follow some<br>conventions.<br>• The tests must either be in a package or be a module called tests.<br>• If tests is a package, then all test modules inside must also have a name starting with test,<br>as it is the case with our name test sample.py.<br>• The test module must be somewhere in the Zope 3 source tree, since the test runner looks<br>only for files there.<br>In our case, you could simply create a tests package in ZOPE3/src (do not forget the<br>init .<br>py file). Then place the test sample.py file into this directory.<br>You you can use the test runner to run only the sample tests as follows from the Zope 3 root<br>directory:<br>python test.py -vp tests.test_sample<br>The -v option stands for verbose mode, so that detailed information about a test failure is<br>provided. The -p option enables a progress bar that tells you how many tests out of all have been<br>completed. There are many more options that can be specified. You can get a full list of them with<br>the option -h: pythontest.py-h.<br>The output of the call above is as follows:<br>nfiguration file found.<br>nning UNIT tests at level 1<br>nning UNIT tests from /opt/zope/Zope3<br>3/3 (100.0%): test_title (tests.test_sample.SampleTest)<br>--------------------------------------------------------------------<br>n 3 tests in 0.002s<br><hr><A name=6></a>6<br>CHAPTER 44. WRITING BASIC UNIT TESTS<br>nning FUNCTIONAL tests at level 1<br>nning FUNCTIONAL tests from /opt/zope/Zope3<br>--------------------------------------------------------------------<br>n 0 tests in 0.000s<br>Line 1: The test runner uses a configuration file for some setup. This allows developers to use<br>the test runner for other projects as well. This message simply tells us that the configuration file<br>was found.<br>Line 2–8: The unit tests are run. On line 4 you can see the progress bar.<br>Line 9–15: The functional tests are run, since the default test runner runs both types of tests.<br>Since we do not have any functional tests in the specified module, there are no tests to run. To<br>just run the unit tests, use option -u and -f for just running the functional tests. See “Writing<br>Functional Tests” for more detials on functional tests.<br><hr><A name=7></a>44.3. RUNNING THE TESTS<br>7<br>Exercises<br>1. It is not very common to do the setup – in our case sample=Sample() – in every test<br>method. Instead there exists a method called setUp() and its counterpart tearDown that<br>are run before and after each test, respectively. Change the test code above, so that it uses<br>the setUp() method. In later chapters and the rest of the book we will frequently use this<br>method of setting up tests.<br>2. Currently the test setDescription() test only verifies that None is not allowed as input<br>value.<br>(a) Improve the test, so that all other builtin types are tested as well.<br>(b) Also, make sure that any objects inheriting from str or unicode pass as valid values.<br><hr>]

IN pdf_to_html(/home/stefan/autotest/temp/python24-zope210-cmf21-plone33next/eggs/Products.PortalTransforms-1.6.6-py2.4.egg/Products/PortalTransforms/tests/input/demo1.pdf)

  Ran 538 tests with 2 failures and 0 errors in 64.117 seconds.
Tearing down left over layers:
  Tear down Products.PloneTestCase.layer.PloneSite in 0.300 seconds.
  Tear down Products.PloneTestCase.layer.ZCML in 0.006 seconds.
Total: 616 tests, 2 failures, 0 errors

FAILED (failures=2)




More information about the Testbot mailing list