testing for pragmatic people
DESCRIPTION
TRANSCRIPT
![Page 1: Testing for Pragmatic People](https://reader033.vdocument.in/reader033/viewer/2022051314/54b601444a795954558b4658/html5/thumbnails/1.jpg)
Michael DavisDevelopment LeaderPlone Conference5th November 2011
Testing for Pragmatic People
![Page 2: Testing for Pragmatic People](https://reader033.vdocument.in/reader033/viewer/2022051314/54b601444a795954558b4658/html5/thumbnails/2.jpg)
Theory
• Code without tests is broken code• 100% test coverage is a minimum• God kills a kitten every time someone checks in code
without a test
• Testing will make you more attractive to the opposite sex
• There's a special place in hell for people who code without tests
![Page 3: Testing for Pragmatic People](https://reader033.vdocument.in/reader033/viewer/2022051314/54b601444a795954558b4658/html5/thumbnails/3.jpg)
Reality
• Testing is hard• Expensive• Slow to run
• Maintaining
• Test framework keeps changing• Refactoring• Tests wrong
![Page 4: Testing for Pragmatic People](https://reader033.vdocument.in/reader033/viewer/2022051314/54b601444a795954558b4658/html5/thumbnails/4.jpg)
Confused Much?
http://www.fl ickr.com/photos/39585662@N00/5331407243
![Page 5: Testing for Pragmatic People](https://reader033.vdocument.in/reader033/viewer/2022051314/54b601444a795954558b4658/html5/thumbnails/5.jpg)
Realism
• Tests are not mandatory
• However, they are ...• Advocated• Best practice
• Helpful
• Eminently sensible
![Page 6: Testing for Pragmatic People](https://reader033.vdocument.in/reader033/viewer/2022051314/54b601444a795954558b4658/html5/thumbnails/6.jpg)
Testing is atool
![Page 7: Testing for Pragmatic People](https://reader033.vdocument.in/reader033/viewer/2022051314/54b601444a795954558b4658/html5/thumbnails/7.jpg)
Cost/Value
Value of TestCost of Test
Testing Experience
![Page 8: Testing for Pragmatic People](https://reader033.vdocument.in/reader033/viewer/2022051314/54b601444a795954558b4658/html5/thumbnails/8.jpg)
What do we meanby Tests
• Unit tests• Integration tests• Mock tests
• Doc tests
• Regression tests
![Page 9: Testing for Pragmatic People](https://reader033.vdocument.in/reader033/viewer/2022051314/54b601444a795954558b4658/html5/thumbnails/9.jpg)
Unit tests
• Much faster than integration tests• For testing a small element of the code base• Testing individual methods
• getToolByName is always a problem
• Get complex quickly• Expensive to maintain
![Page 10: Testing for Pragmatic People](https://reader033.vdocument.in/reader033/viewer/2022051314/54b601444a795954558b4658/html5/thumbnails/10.jpg)
Doc tests
• Primarily for describing functionality using python calls
• Fails at first failure
• Difficult to write
• Good for documentation
![Page 11: Testing for Pragmatic People](https://reader033.vdocument.in/reader033/viewer/2022051314/54b601444a795954558b4658/html5/thumbnails/11.jpg)
Regression Tests
• Not actually a test• About when and why
![Page 12: Testing for Pragmatic People](https://reader033.vdocument.in/reader033/viewer/2022051314/54b601444a795954558b4658/html5/thumbnails/12.jpg)
Mock Testing
• Using mock objects to run tests• Useful in unit testing to mock required objects• Can mock getToolByName to return the right tool
• Used to test the untestable
![Page 13: Testing for Pragmatic People](https://reader033.vdocument.in/reader033/viewer/2022051314/54b601444a795954558b4658/html5/thumbnails/13.jpg)
Integration Tests
• Often called unit tests• Full Plone instance setup
![Page 14: Testing for Pragmatic People](https://reader033.vdocument.in/reader033/viewer/2022051314/54b601444a795954558b4658/html5/thumbnails/14.jpg)
What about Test Driven
Development
![Page 15: Testing for Pragmatic People](https://reader033.vdocument.in/reader033/viewer/2022051314/54b601444a795954558b4658/html5/thumbnails/15.jpg)
Mindsets
• Writing code - how• Writing test – what• Effects versus Mechanics
![Page 16: Testing for Pragmatic People](https://reader033.vdocument.in/reader033/viewer/2022051314/54b601444a795954558b4658/html5/thumbnails/16.jpg)
Keep It Simple
• Minimise effort• Maximise reuse
![Page 17: Testing for Pragmatic People](https://reader033.vdocument.in/reader033/viewer/2022051314/54b601444a795954558b4658/html5/thumbnails/17.jpg)
Test Framework
class TestCase(PloneSandboxLayer):
defaultBases = (PLONE_FIXTURE,)
def setUpZope(self, app, confgurationContext):
import my.product
self.loadZCML(package=my.product)
z2.installProduct(app, PROJECTNAME)
def setUpPloneSite(self, portal):
self.applyProfle(portal, '%s:default' % PROJECTNAME)
def tearDownZope(self, app):
z2.uninstallProduct(app, PROJECTNAME)
![Page 18: Testing for Pragmatic People](https://reader033.vdocument.in/reader033/viewer/2022051314/54b601444a795954558b4658/html5/thumbnails/18.jpg)
Test Framework
from plone.app.testing import PloneSandboxLayer
from plone.app.testing import PLONE_FIXTURE
from plone.app.testing import IntegrationTesting
from plone.testing import z2
from my.product.confg import PROJECTNAME
class TestCase(PloneSandboxLayer):
....
FIXTURE = TestCase()
INTEGRATION_TESTING = IntegrationTesting(bases=(FIXTURE,), name="fxture:Integration")
![Page 19: Testing for Pragmatic People](https://reader033.vdocument.in/reader033/viewer/2022051314/54b601444a795954558b4658/html5/thumbnails/19.jpg)
Simple Test
class TestReinstall(unittest.TestCase):
"""Ensure product can be reinstalled safely"""
layer = INTEGRATION_TESTING
def setUp(self):
self.portal = self.layer['portal']
def testReinstall(self):
portal_setup = getToolByName(self.portal, 'portal_setup')
portal_setup.runAllImportStepsFromProfle('profle-%s:default' % PROJECTNAME)
![Page 20: Testing for Pragmatic People](https://reader033.vdocument.in/reader033/viewer/2022051314/54b601444a795954558b4658/html5/thumbnails/20.jpg)
Running Tests
bin/test -s my.product
Ran 2 tests with 0 failures and 0 errors in 1.050 seconds.
Tearing down left over layers:
Tear down collective.wfform.tests.base.fixture:Integration in 0.000 seconds.
Tear down collective.wfform.tests.base.TestCase in 0.013 seconds.
Tear down plone.app.testing.layers.PloneFixture in 0.380 seconds.
Tear down plone.testing.z2.Startup in 0.024 seconds.
Tear down plone.testing.zca.LayerCleanup in 0.006 seconds.
![Page 21: Testing for Pragmatic People](https://reader033.vdocument.in/reader033/viewer/2022051314/54b601444a795954558b4658/html5/thumbnails/21.jpg)
Browser Layer
class TestInstallation(unittest.TestCase):
"""Ensure product is properly installed"""
layer = INTEGRATION_TESTING
def setUp(self):
self.portal = self.layer['portal']
def testBrowserLayerRegistered(self):
sm = getSiteManager(self.portal)
layers = [o.__name__ for o in registered_layers()]
assert 'IMyProduct' in layers
![Page 22: Testing for Pragmatic People](https://reader033.vdocument.in/reader033/viewer/2022051314/54b601444a795954558b4658/html5/thumbnails/22.jpg)
Skin Layer
class TestInstallation(unittest.TestCase):
"""Ensure product is properly installed"""
layer = INTEGRATION_TESTING
def setUp(self):
self.portal = self.layer['portal']
def testSkinLayersInstalled(self):
assert 'my_skin' in self.portal.portal_skins.objectIds()
assert 'my_template' in self.portal.portal_skins.my_skin.objectIds()
![Page 23: Testing for Pragmatic People](https://reader033.vdocument.in/reader033/viewer/2022051314/54b601444a795954558b4658/html5/thumbnails/23.jpg)
Portal Type
class TestInstallation(unittest.TestCase):
"""Ensure product is properly installed"""
layer = INTEGRATION_TESTING
def setUp(self):
self.portal = self.layer['portal']
def testTypesInstalled(self):
portal_types = getToolByName(self.portal, 'portal_types')
assert 'MyType' in portal_types.objectIds(), portal_types.objectIds()
![Page 24: Testing for Pragmatic People](https://reader033.vdocument.in/reader033/viewer/2022051314/54b601444a795954558b4658/html5/thumbnails/24.jpg)
Portal Types
class TestContentType(unittest.TestCase):
"""Test content type"""
layer = INTEGRATION_TESTING
def setUp(self):
self.portal = self.layer['portal']
def testAddType(self):
setRoles(self.portal, TEST_USER_ID, ['Manager'])
self.portal.invokeFactory('MyType', 'mt1')
mt1 = getattr(self.portal, 'mt1')
mt1.setTitle('The Title of My Object')
Assert mt1.Title() == 'The Title of My Object', mt1.Title()
![Page 25: Testing for Pragmatic People](https://reader033.vdocument.in/reader033/viewer/2022051314/54b601444a795954558b4658/html5/thumbnails/25.jpg)
Schema
class TestContentSchema(unittest.TestCase):
"""Test content type schema"""
layer = INTEGRATION_TESTING
def setUp(self):
self.portal = self.layer['portal']
setRoles(self.portal, TEST_USER_ID, ['Manager'])
self.portal.invokeFactory('MyType', 'mt1')
self.mt1 = getattr(self.portal, 'mt1')
def testSchema(self):
schema = self.mt1.schema
feld_ids = schema.keys()
assert 'referenceNumber' in feld_ids
![Page 26: Testing for Pragmatic People](https://reader033.vdocument.in/reader033/viewer/2022051314/54b601444a795954558b4658/html5/thumbnails/26.jpg)
Form Validation
class TestValidation(unittest.TestCase):
"""Test validation"""
layer = INTEGRATION_TESTING
def setUp(self):
self.portal = self.layer['portal']
setRoles(self.portal, TEST_USER_ID, ['Manager'])
self.portal.invokeFactory('MyType', 'mt1')
self.mt1 = getattr(self.portal, 'mt1')
app = makerequest(self.app)
app.REQUEST.form['name'] = 'Michael Davis'
![Page 27: Testing for Pragmatic People](https://reader033.vdocument.in/reader033/viewer/2022051314/54b601444a795954558b4658/html5/thumbnails/27.jpg)
Validation Test
def testValidates(self):
dummy_controller_state = ControllerState(
id='my_form',
context=s1,
button='submit',
status='success',
errors={},
next_action=None,)
controller = self.portal.portal_form_controller object
controller_state = controller.validate(dummy_controller_state, app.REQUEST, ['my_validate',])
assert controller_state.getErrors() == {}, controller_state.getErrors()
![Page 28: Testing for Pragmatic People](https://reader033.vdocument.in/reader033/viewer/2022051314/54b601444a795954558b4658/html5/thumbnails/28.jpg)
Test Patterns
def testValidatePrisoner(self):
app.REQUEST.form['name'] = 6
…
assert len(controller_state.getErrors()) == 1
assert controller_state.getErrors().has_key('name')
assert controller_state.getErrors()['name'] == 'You are not a number'
![Page 29: Testing for Pragmatic People](https://reader033.vdocument.in/reader033/viewer/2022051314/54b601444a795954558b4658/html5/thumbnails/29.jpg)
Test Patterns
def testValidateClint(self):
app.REQUEST.form['name'] = ''
…
assert len(controller_state.getErrors()) == 1
assert controller_state.getErrors().has_key('name')
assert controller_state.getErrors()['name'] == 'You are not the man with no name'
![Page 30: Testing for Pragmatic People](https://reader033.vdocument.in/reader033/viewer/2022051314/54b601444a795954558b4658/html5/thumbnails/30.jpg)
CI Server
![Page 31: Testing for Pragmatic People](https://reader033.vdocument.in/reader033/viewer/2022051314/54b601444a795954558b4658/html5/thumbnails/31.jpg)
Use your tools responsibly
http://www.fl ickr.com/photos/12803689@N02/4402962654