This document discusses testing practices for pragmatic developers. It argues that while testing is important, it should be done pragmatically by focusing on value over completeness. Unit, integration, mock and other types of tests are described along with test frameworks and best practices like test-driven development. The document emphasizes that testing needs to balance costs and value.
2. 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
3. Reality
• Testing is hard
• Expensive
• Slow to run
• Maintaining
• Test framework keeps changing
• Refactoring
• Tests wrong
4. Confused Much?
http://www.f ickr.com/photos/39585662@N00/5331407243
l
5. Realism
• Tests are not mandatory
• However, they are ...
• Advocated
• Best practice
• Helpful
• Eminently sensible
7. Cost/Value
Value of Test
Cost of Test
Testing Experience
8. What do we mean
by Tests
• Unit tests
• Integration tests
• Mock tests
• Doc tests
• Regression tests
9. 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
10. Doc tests
• Primarily for describing functionality using python
calls
• Fails at first failure
• Difficult to write
• Good for documentation
12. 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
13. Integration Tests
• Often called unit tests
• Full Plone instance setup
18. 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")
19. 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)
20. 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.
21. 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
22. 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()
23. 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()
24. 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()
28. 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'
29. 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'