plone testingdzug tagung2010

Post on 08-May-2015

647 Views

Category:

Documents

0 Downloads

Preview:

Click to see full reader

TRANSCRIPT

Plone Testing

DZUG Tagung Dresden 2010

Timo Stollenwerk

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

Material

● Folien:● slideshare.net/tisto

● Code:● svn.plone.org/svn/collective/examples/example.dzu

gconference/example.dzugconference

Was ist ein Test?

Test Beispiel

def is_palindrome(word):

pass

def test_palindromic_word():

assert is_palindrome("noon") == True

assert is_palindrome("foo") == False

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)

Warum sind Tests wichtig?

Warum Testen?

● Robusterer Code● Besseres Code Verständnis● Nachweis● Dokumentation von Software Anforderungen● „Billigeres“ Bugfixing● Refactoring

Was ist Test-Driven Development?

Test-Driven Development

Kent Beck: Test Driven Development

Arten von Tests

Funktionale Tests

● Funktionaler Ablauf● Benutzersicht● BlackBox Testing● Akzeptanztests

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

User Stories mit (Doc)Tests

As a logged-in user, I can add a new page to the website.

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

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

zope.testbrowser debugging

open('/tmp/testbrowser.html','w').write(browser.contents)

Interlude (Interaktives Debugging)

import interlude

suite = DocFileSuite(...,

globs={'interact': interlude.interact},

...)

>>> interact( locals() )

http://pypi.python.org/pypi/interlude/

Testing Pyramide

Integrationstests

● Testet die Zusammenarbeit voneinander abhängiger Komponenten

Beispiel Integrationstest

class IPresenter(form.Schema):

title = schema.TextLine(

title=_(u"Title")

)

...

Was wollen wir testen?

● Schema● Typ Registrierung (FTI)● Factory● Hinzufügen des Inhaltstyps● View

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']

Integrationstest: Schema

def test_schema(self):

fti = queryUtility(IDexterityFTI,

name='example.dzugconference.presenter')

schema = fti.lookupSchema()

self.assertEquals(IPresenter, schema)

Integrationstest: FTI

def test_fti(self):

fti = queryUtility(IDexterityFTI,

name='example.dzugconference.presenter')

self.assertNotEquals(None, fti)

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))

Integrationstest: Hinzufügen

def test_adding(self):

self.folder.invokeFactory(

'example.dzugconference.presenter',

'presenter1')

p1 = self.folder['presenter1']

self.failUnless(IPresenter.providedBy(p1))

Integrationstest: View

def test_view(self):

self.folder.invokeFactory(

'example.dzugconference.presenter',

'presenter1')

p1 = self.folder['presenter1']

view = p1.restrictedTraverse('@@view')

self.failUnless(view)

Integrationstest: Debugging

def test_todo(self):

import pdb; pdb.set_trace()

import ipdb; ipdb.set_trace()

Testing Pyramide

Unit Tests in Plone

● Test einer isolierten Komponente● Wie?● => Mock Objects

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

Setup Tests

● Professional Plone Development● Layer / collective.testcaselayer● plone.testing / plone.app.testing

Test Setup (PPD)

TestPortlet(CinemaContentTestCase):

def afterSetUp(self):

...

PPD: Optilux Code Examples

Test Setup (Layer)

class CommentTest(PloneTestCase):

layer = DiscussionLayer

def afterSetUp(self):

...

http://svn.plone.org/svn/plone/plone.app.discussion/trunk

Test Setup (plone.testing)

class ExampleDzugConference(PloneSandboxLayer):

defaultBases = (PLONE_FIXTURE,)

def setUpPloneSite(self, portal):

...

Collective SVN: examples/examples.dzugconference

Testrunner

parts += test

[test]

recipe = zc.recipe.testrunner

eggs = ${instance:eggs}

defaults = ['--auto-color', '--auto-progress']

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)

Testing Pyramide

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')

Hudson Continuous Integration

http://hudson.zmag.de/hudson

Weitere Tests

● Python● Pylint

● Templates● ZPTLint

● Javascript● JSLint● qUnit

svn.plone.org/svn/plone/plone.app.discussion/trunk/test-plone-4.0.x.cfg

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

Fragen?

top related