UPC Testing talk 2

Post on 08-May-2015

1.527 views 0 download

Transcript of UPC Testing talk 2

   

Testing for fun and profit – Part 2

April, 27th 2010

Timo Stollenwerk

   

Part 1 – Why testing matters

● Reduces defects● Find bugs early● Proof that you delivered what you were 

contracted to produce● Refactor with confidence● Lots of small successes

   

Testing pyramid

   

What are you going to learn today?

● Set up integration and functional tests● Traditional test setup● Test setup with layers

● Testing● Policy product● Dexterity types● Archetypes● Portlets

   

The current state of testing in Plone

● Plone 3 / PPD / Paster● collective.testcaselayer● plone.testing

   

Plone 3 test structure

$ paster create ­t archetype upc.myarchetype 

● tests● __init__.py● base.py● test_doctest.py

   

Test setup: base.py

● Import ZopeTestCase and PloneTestCase● setup_product function● setupPloneSite● TestCase & FunctionalTestCase

   

Test setup: base.py (import)

from Testing import ZopeTestCase as ztc

from Products.PloneTestCase import PloneTestCase as ptc

from Products.PloneTestCase.layer import onsetup

   

Test setup: base.py (setup_product)

@onsetup

def setup_product():

    fiveconfigure.debug_mode = True

    import upc.myarchetype

    zcml.load_config('configure.zcml', upcexample.myarchetype)

    fiveconfigure.debug_mode = False

    ztc.installPackage('upcexample.theme')

   

Test setup: base.py (test classes)

class TestCase(ptc.PloneTestCase):

    """We use this base class for all the tests in this package. If

    necessary, we can put common utility or setup code in here. This

    applies to unit test cases.

    """

class FunctionalTestCase(ptc.FunctionalTestCase):

    """We use this class for functional integration tests that use

    doctest syntax. Again, we can put basic common utility or setup

    code in here.

    ""”

   

TestCasefrom upcexample.myproduct.tests.base import TestCase

class TestSetup(TestCase):

    

    def afterSetUp(self):

        self.workflow = getToolByName(self.portal, 'portal_workflow')

    

    def test_portal_title(self):

        self.assertEquals("UPC Portal", self.portal.getProperty('title'))

def test_suite():

    suite = unittest.TestSuite()

    suite.addTest(unittest.makeSuite(TestSetup))

    return suite

   

FunctionalTestCaseimport unittest

import doctest

from Testing import ZopeTestCase as ztc

from upctest.myproduct.tests import base

def test_suite():

    return unittest.TestSuite([

        # Demonstrate the main content types

        ztc.ZopeDocFileSuite(

            'README.txt', package=upctest.myproduct',

            test_class=base.FunctionalTestCase,

            optionflags=doctest.REPORT_ONLY_FIRST_FAILURE |

                doctest.NORMALIZE_WHITESPACE | doctest.ELLIPSIS),

        ])

if __name__ == '__main__':

    unittest.main(defaultTest='test_suite')

   

FunctionalTestCase Doctest

Being a doctest, we can tell a story here.

>>> from Products.Five.testbrowser import Browser

>>> browser = Browser()

>>> portal_url = self.portal.absolute_url()

   

FunctionalTestCase: Login

    >>> from Products.PloneTestCase.setup import portal_owner, default_password

    >>> browser.open(portal_url)

We have the login portlet, so let's use that.

    >>> browser.getControl(name='__ac_name').value = portal_owner

    >>> browser.getControl(name='__ac_password').value = default_password

    >>> browser.getControl(name='submit').click()

   

FunctionalTestCase: Properties

    >>> browser.url == portal_url

    True

    >>> "You are now logged in" in browser.contents

    True

    >>> 'foo' in browser.headers

    False

   

FunctionalTestCase: Actions

­ browser.open(url)

­ browser.reload()

­ browser.goBack(count=1)

­ browser.getLink(text=None, url=None, id=None)

­ browser.click()

­ browser.getControl(label=None, name=None, index=None)

   

Zope Testrunner (Plone 3)

● Test package

$ ./bin/instance test ­s upcexample.myproduct

   

Zope Testrunner (Plone 3)

● Test single file

$ ./bin/instance test ­s upcexample.myproduct ­t test_setup

   

Zope Testrunner (Plone 3)

● Unit/Integration tests only

$ ./bin/instance test ­s upcexample.myproduct ­u

   

Zope Testrunner (Plone 3)

● Debug

$ ./bin/instance test ­D

   

Setting Up Tests with Layers

● Tests (upc.testingtutorial / example.conference)● __init__.py● layer.py● test_functional_doctest.py● functional.txt● test_task.py

   

Setting Up Tests with Layers: layer.py

# Imports

ptc.setupPloneSite(

    extension_profiles=('upc.testingtutorial:default', )

)

class IntegrationTestLayer(collective.testcaselayer.ptc.BasePTCLayer):

    def afterSetUp(self):

        self.addProfile('upc.testingtutorial:default')

Layer = IntegrationTestLayer([collective.testcaselayer.ptc.ptc_layer])

   

Setting Up Tests with Layers: test_functional_doctest.py

# Imports

from upc.testingtutorial.tests.layer import Layer

def test_suite():

    return unittest.TestSuite([

        ztc.ZopeDocFileSuite(

            'functional.txt', package='upc.testingtutorial.tests',

            test_class=ptc.FunctionalTestCase,

            optionflags=doctest.REPORT_ONLY_FIRST_FAILURE | doctest.NORMALIZE_WHITESPACE | doctest.ELLIPSIS),

        ])

   

Setting Up Tests with Layers: functional.txt

==========================================

 UPC Testing Tutorial: Functional Doctest

==========================================

This package contains a functional doctest for the task content type of the

upc.testringtutorial package. In this testbrowser doctest, we will demonstrate 

how the task content type works. See tests/test_functional_doctest.py for how 

it is set up.

    >>> from Products.Five.testbrowser import Browser

    >>> browser = Browser()

    >>> portal_url = self.portal.absolute_url()

   

Setting Up Tests with Layers: test_task.py

class TestTaskIntegration(PloneTestCase):

    

    layer = Layer

    

    def test_adding(self):

        self.folder.invokeFactory('upc.testingtutorial.task', 'task1')

        t1 = self.folder['task1']

        self.failUnless(ITask.providedBy(t1))

    

def test_suite():

    return unittest.defaultTestLoader.loadTestsFromName(__name__)

   

Zope Testrunner (Plone 4)

[buildout]

parts = 

    ...

    test

[test]

recipe = zc.recipe.testrunner

eggs =  upcexample.myproduct

defaults = ['­v', '­­exit­with­status', '­­auto­color', '­­auto­progress']

   

Zope Testrunner (Plone 4)

● Run all tests

$ ./bin/test● Test one package

$ ./bin/test ­s upcexample.mypackage

...

   

Testing Portlets

class TestPortlet(TestCase):

    def afterSetUp(self):

        self.setRoles(('Manager',))

    …

class TestRenderer(TestCase):    

    def afterSetUp(self):

        self.setRoles(('Manager',))

        self.portal.invokeFactory('Folder', 'cf1')

    ....

http://svn.plone.org/svn/collective/collective.portlet.recentactivity/trunk/collective/portlet/recentactivity/tests/test_portlet_recent_activity.py

   

Testing Viewlets

class TestCommentsViewletIntegration(FunctionalTestCase):

    layer = DiscussionLayer

    def testCommentsViewlet(self):

        browser = Browser()

        portal_url = self.portal.absolute_url()

        browser.handleErrors = False

        from Products.PloneTestCase.setup import portal_owner, default_password

        browser.open(portal_url + '/login_form')

http://svn.plone.org/svn/plone/plone.app.discussion/trunk/plone/app/discussion/tests/test_comments_viewlet.py

   

Summary

● Setting up tests● Traditional way (PPD / Optilux / ZopeSkel)

● Testcaselayer (Dexterity manual)

● Future: plone.testing

● Archetypes● PPD / Optilux / ZopeSkel

● Dexterity● Dexterity manual (example.conference)

● Portlet● ZopeSkel / Paster output

● Viewlet● plone.app.discussion / plone.app.layout (search for *test*.py)

   

Testing Resources

● Plone Testing Tutorial● http://plone.org/documentation/kb/testing

● Plone 3 / Archetypes ● PPD / Optilux

● Plone 4 / Dexterity Manual / example.conference● http://plone.org/products/dexterity/documentation/manual/developer­manual● http://svn.plone.org/svn/collective/example.conference/ 

   

The End