Download - Plone testingdzug tagung2010
![Page 1: Plone testingdzug tagung2010](https://reader035.vdocuments.us/reader035/viewer/2022081400/554bc0f6b4c90594278b5151/html5/thumbnails/1.jpg)
Plone Testing
DZUG Tagung Dresden 2010
Timo Stollenwerk
![Page 2: Plone testingdzug tagung2010](https://reader035.vdocuments.us/reader035/viewer/2022081400/554bc0f6b4c90594278b5151/html5/thumbnails/2.jpg)
Timo Stollenwerk
● Plone Entwickler seit 2004● GSoC 2009: plone.app.discussion
● ~ 120 Tests● Python und Javascript● Code Analysis (Pylint, ZPTLint, JSLint)● Code Coverage● Continuous Integration
![Page 3: Plone testingdzug tagung2010](https://reader035.vdocuments.us/reader035/viewer/2022081400/554bc0f6b4c90594278b5151/html5/thumbnails/3.jpg)
Material
● Folien:● slideshare.net/tisto
● Code:● svn.plone.org/svn/collective/examples/example.dzu
gconference/example.dzugconference
![Page 4: Plone testingdzug tagung2010](https://reader035.vdocuments.us/reader035/viewer/2022081400/554bc0f6b4c90594278b5151/html5/thumbnails/4.jpg)
Was ist ein Test?
![Page 5: Plone testingdzug tagung2010](https://reader035.vdocuments.us/reader035/viewer/2022081400/554bc0f6b4c90594278b5151/html5/thumbnails/5.jpg)
Test Beispiel
def is_palindrome(word):
pass
def test_palindromic_word():
assert is_palindrome("noon") == True
assert is_palindrome("foo") == False
![Page 6: Plone testingdzug tagung2010](https://reader035.vdocuments.us/reader035/viewer/2022081400/554bc0f6b4c90594278b5151/html5/thumbnails/6.jpg)
Python Unittest Testcase
http://docs.python.org/library/unittest.html
import unittest
class TestIsPalindrome(unittest.TestCase):
def test_palindromic_word():
self.assertEquals(is_palindrome("noon"), True)
self.failIf(is_palindrome("foo"))
def test_non_string_raises_exception():
self.UnlessRaises(TypeError, is_palindrome, 2)
![Page 7: Plone testingdzug tagung2010](https://reader035.vdocuments.us/reader035/viewer/2022081400/554bc0f6b4c90594278b5151/html5/thumbnails/7.jpg)
Warum sind Tests wichtig?
![Page 8: Plone testingdzug tagung2010](https://reader035.vdocuments.us/reader035/viewer/2022081400/554bc0f6b4c90594278b5151/html5/thumbnails/8.jpg)
Warum Testen?
● Robusterer Code● Besseres Code Verständnis● Nachweis● Dokumentation von Software Anforderungen● „Billigeres“ Bugfixing● Refactoring
![Page 9: Plone testingdzug tagung2010](https://reader035.vdocuments.us/reader035/viewer/2022081400/554bc0f6b4c90594278b5151/html5/thumbnails/9.jpg)
Was ist Test-Driven Development?
![Page 10: Plone testingdzug tagung2010](https://reader035.vdocuments.us/reader035/viewer/2022081400/554bc0f6b4c90594278b5151/html5/thumbnails/10.jpg)
Test-Driven Development
Kent Beck: Test Driven Development
![Page 11: Plone testingdzug tagung2010](https://reader035.vdocuments.us/reader035/viewer/2022081400/554bc0f6b4c90594278b5151/html5/thumbnails/11.jpg)
Arten von Tests
![Page 12: Plone testingdzug tagung2010](https://reader035.vdocuments.us/reader035/viewer/2022081400/554bc0f6b4c90594278b5151/html5/thumbnails/12.jpg)
Funktionale Tests
● Funktionaler Ablauf● Benutzersicht● BlackBox Testing● Akzeptanztests
![Page 13: Plone testingdzug tagung2010](https://reader035.vdocuments.us/reader035/viewer/2022081400/554bc0f6b4c90594278b5151/html5/thumbnails/13.jpg)
XP/Scrum und Funktionale Tests
● Abbildung von (Software) Anforderungen durch User Stories / Acceptance Tests
● Testbare Spezifikation● Code der die Tests besteht● => Beweist das die Software tut was sie soll
![Page 14: Plone testingdzug tagung2010](https://reader035.vdocuments.us/reader035/viewer/2022081400/554bc0f6b4c90594278b5151/html5/thumbnails/14.jpg)
User Stories mit (Doc)Tests
As a logged-in user, I can add a new page to the website.
![Page 15: Plone testingdzug tagung2010](https://reader035.vdocuments.us/reader035/viewer/2022081400/554bc0f6b4c90594278b5151/html5/thumbnails/15.jpg)
Beispiel Funktionaler Doctest
>>> browser.open(portal_url)
>>> browser.getLink(id='example-dzugconference-presenter').click()
>>> browser.getControl(name='form.widgets.title').value = "Presenter 1"
>>> browser.getControl(name='form.buttons.save').click()
Plone SVN: plone.app.discussion/.../presenter.txt
![Page 16: Plone testingdzug tagung2010](https://reader035.vdocuments.us/reader035/viewer/2022081400/554bc0f6b4c90594278b5151/html5/thumbnails/16.jpg)
zope.testbrowser
● browser.open('http://nohost/plone/')● browser.getLink(link_text).click()● browser.url● browser.reload()● browser.getControl(input_name).value =
‘Whatever’● browser.getControl(name='form.buttons.save').
click()
http://pypi.python.org/pypi/zope.testbrowser
![Page 17: Plone testingdzug tagung2010](https://reader035.vdocuments.us/reader035/viewer/2022081400/554bc0f6b4c90594278b5151/html5/thumbnails/17.jpg)
zope.testbrowser debugging
open('/tmp/testbrowser.html','w').write(browser.contents)
![Page 18: Plone testingdzug tagung2010](https://reader035.vdocuments.us/reader035/viewer/2022081400/554bc0f6b4c90594278b5151/html5/thumbnails/18.jpg)
Interlude (Interaktives Debugging)
import interlude
suite = DocFileSuite(...,
globs={'interact': interlude.interact},
...)
>>> interact( locals() )
http://pypi.python.org/pypi/interlude/
![Page 19: Plone testingdzug tagung2010](https://reader035.vdocuments.us/reader035/viewer/2022081400/554bc0f6b4c90594278b5151/html5/thumbnails/19.jpg)
Testing Pyramide
![Page 20: Plone testingdzug tagung2010](https://reader035.vdocuments.us/reader035/viewer/2022081400/554bc0f6b4c90594278b5151/html5/thumbnails/20.jpg)
Integrationstests
● Testet die Zusammenarbeit voneinander abhängiger Komponenten
![Page 21: Plone testingdzug tagung2010](https://reader035.vdocuments.us/reader035/viewer/2022081400/554bc0f6b4c90594278b5151/html5/thumbnails/21.jpg)
Beispiel Integrationstest
class IPresenter(form.Schema):
title = schema.TextLine(
title=_(u"Title")
)
...
![Page 22: Plone testingdzug tagung2010](https://reader035.vdocuments.us/reader035/viewer/2022081400/554bc0f6b4c90594278b5151/html5/thumbnails/22.jpg)
Was wollen wir testen?
● Schema● Typ Registrierung (FTI)● Factory● Hinzufügen des Inhaltstyps● View
![Page 23: Plone testingdzug tagung2010](https://reader035.vdocuments.us/reader035/viewer/2022081400/554bc0f6b4c90594278b5151/html5/thumbnails/23.jpg)
Integrationstests: setUp
def setUp(self):
self.portal = self.layer['portal']
setRoles(self.portal, TEST_USER_NAME, ['Manager'])
self.portal.invokeFactory('Folder', 'test-folder')
setRoles(self.portal, TEST_USER_NAME, ['Member'])
self.folder = self.portal['test-folder']
![Page 24: Plone testingdzug tagung2010](https://reader035.vdocuments.us/reader035/viewer/2022081400/554bc0f6b4c90594278b5151/html5/thumbnails/24.jpg)
Integrationstest: Schema
def test_schema(self):
fti = queryUtility(IDexterityFTI,
name='example.dzugconference.presenter')
schema = fti.lookupSchema()
self.assertEquals(IPresenter, schema)
![Page 25: Plone testingdzug tagung2010](https://reader035.vdocuments.us/reader035/viewer/2022081400/554bc0f6b4c90594278b5151/html5/thumbnails/25.jpg)
Integrationstest: FTI
def test_fti(self):
fti = queryUtility(IDexterityFTI,
name='example.dzugconference.presenter')
self.assertNotEquals(None, fti)
![Page 26: Plone testingdzug tagung2010](https://reader035.vdocuments.us/reader035/viewer/2022081400/554bc0f6b4c90594278b5151/html5/thumbnails/26.jpg)
Integrationstest: Factory
def test_factory(self):
fti = queryUtility(IDexterityFTI,
name='example.dzugconference.presenter')
factory = fti.factory
new_object = createObject(factory)
self.failUnless(
IPresenter.providedBy(new_object))
![Page 27: Plone testingdzug tagung2010](https://reader035.vdocuments.us/reader035/viewer/2022081400/554bc0f6b4c90594278b5151/html5/thumbnails/27.jpg)
Integrationstest: Hinzufügen
def test_adding(self):
self.folder.invokeFactory(
'example.dzugconference.presenter',
'presenter1')
p1 = self.folder['presenter1']
self.failUnless(IPresenter.providedBy(p1))
![Page 28: Plone testingdzug tagung2010](https://reader035.vdocuments.us/reader035/viewer/2022081400/554bc0f6b4c90594278b5151/html5/thumbnails/28.jpg)
Integrationstest: View
def test_view(self):
self.folder.invokeFactory(
'example.dzugconference.presenter',
'presenter1')
p1 = self.folder['presenter1']
view = p1.restrictedTraverse('@@view')
self.failUnless(view)
![Page 29: Plone testingdzug tagung2010](https://reader035.vdocuments.us/reader035/viewer/2022081400/554bc0f6b4c90594278b5151/html5/thumbnails/29.jpg)
Integrationstest: Debugging
def test_todo(self):
import pdb; pdb.set_trace()
import ipdb; ipdb.set_trace()
![Page 30: Plone testingdzug tagung2010](https://reader035.vdocuments.us/reader035/viewer/2022081400/554bc0f6b4c90594278b5151/html5/thumbnails/30.jpg)
Testing Pyramide
![Page 31: Plone testingdzug tagung2010](https://reader035.vdocuments.us/reader035/viewer/2022081400/554bc0f6b4c90594278b5151/html5/thumbnails/31.jpg)
Unit Tests in Plone
● Test einer isolierten Komponente● Wie?● => Mock Objects
![Page 32: Plone testingdzug tagung2010](https://reader035.vdocuments.us/reader035/viewer/2022081400/554bc0f6b4c90594278b5151/html5/thumbnails/32.jpg)
Mock und Fake Objekte
● Externe Datenbanken● Web Services● Plone Komponenten● Netzwerkverbindungen● Benötigen externe Komponenten
http://plone.org/products/dexterity/documentation/manual/developer-manual/testing/mock-testing
http://pypi.python.org/pypi/plone.mocktestcase
![Page 33: Plone testingdzug tagung2010](https://reader035.vdocuments.us/reader035/viewer/2022081400/554bc0f6b4c90594278b5151/html5/thumbnails/33.jpg)
Setup Tests
● Professional Plone Development● Layer / collective.testcaselayer● plone.testing / plone.app.testing
![Page 34: Plone testingdzug tagung2010](https://reader035.vdocuments.us/reader035/viewer/2022081400/554bc0f6b4c90594278b5151/html5/thumbnails/34.jpg)
Test Setup (PPD)
TestPortlet(CinemaContentTestCase):
def afterSetUp(self):
…
...
PPD: Optilux Code Examples
![Page 35: Plone testingdzug tagung2010](https://reader035.vdocuments.us/reader035/viewer/2022081400/554bc0f6b4c90594278b5151/html5/thumbnails/35.jpg)
Test Setup (Layer)
class CommentTest(PloneTestCase):
layer = DiscussionLayer
def afterSetUp(self):
…
...
http://svn.plone.org/svn/plone/plone.app.discussion/trunk
![Page 36: Plone testingdzug tagung2010](https://reader035.vdocuments.us/reader035/viewer/2022081400/554bc0f6b4c90594278b5151/html5/thumbnails/36.jpg)
Test Setup (plone.testing)
class ExampleDzugConference(PloneSandboxLayer):
defaultBases = (PLONE_FIXTURE,)
def setUpPloneSite(self, portal):
…
...
Collective SVN: examples/examples.dzugconference
![Page 37: Plone testingdzug tagung2010](https://reader035.vdocuments.us/reader035/viewer/2022081400/554bc0f6b4c90594278b5151/html5/thumbnails/37.jpg)
Testrunner
parts += test
[test]
recipe = zc.recipe.testrunner
eggs = ${instance:eggs}
defaults = ['--auto-color', '--auto-progress']
![Page 38: Plone testingdzug tagung2010](https://reader035.vdocuments.us/reader035/viewer/2022081400/554bc0f6b4c90594278b5151/html5/thumbnails/38.jpg)
Test Geschwindigkeit
Integrations-Tests vs. Funktionale Tests
● plone.app.discussion● Test Setup (Plone Site): 9,5 Sekunden● 116 Integrationstests: 15 Sekunden (+ 6,5)● 1 Funktionaler Test: 21.5 Sekunden (+ 12,0)
![Page 39: Plone testingdzug tagung2010](https://reader035.vdocuments.us/reader035/viewer/2022081400/554bc0f6b4c90594278b5151/html5/thumbnails/39.jpg)
Testing Pyramide
![Page 40: Plone testingdzug tagung2010](https://reader035.vdocuments.us/reader035/viewer/2022081400/554bc0f6b4c90594278b5151/html5/thumbnails/40.jpg)
Test Abdeckung
buildout.cfg
[coverage-test]
recipe = zc.recipe.testrunner
eggs = ${test:eggs}
defaults = ['--coverage', '../../coverage', '-v', '--auto-progress']
[coverage-report]
recipe = zc.recipe.egg
eggs = z3c.coverage
arguments = ('coverage', 'report')
![Page 41: Plone testingdzug tagung2010](https://reader035.vdocuments.us/reader035/viewer/2022081400/554bc0f6b4c90594278b5151/html5/thumbnails/41.jpg)
Hudson Continuous Integration
http://hudson.zmag.de/hudson
![Page 42: Plone testingdzug tagung2010](https://reader035.vdocuments.us/reader035/viewer/2022081400/554bc0f6b4c90594278b5151/html5/thumbnails/42.jpg)
Weitere Tests
● Python● Pylint
● Templates● ZPTLint
● Javascript● JSLint● qUnit
svn.plone.org/svn/plone/plone.app.discussion/trunk/test-plone-4.0.x.cfg
![Page 43: Plone testingdzug tagung2010](https://reader035.vdocuments.us/reader035/viewer/2022081400/554bc0f6b4c90594278b5151/html5/thumbnails/43.jpg)
Weiterführendes Material
● Kent Beck: Test Driven Development● Python Testing: Beginner's Guide● Tarek Ziadé: Expert Python Programming● Testing in Plone:
http://plone.org/documentation/kb/testing● Dexterity Manual - Testing:
http://plone.org/products/dexterity/documentation/manual/developer-manual/testing
![Page 44: Plone testingdzug tagung2010](https://reader035.vdocuments.us/reader035/viewer/2022081400/554bc0f6b4c90594278b5151/html5/thumbnails/44.jpg)
Fragen?