If you can't read please download the document
Upload
quintagroup
View
3.556
Download
10
Embed Size (px)
Citation preview
Default
Intro to Testing
in Zope, Plone
Andriy Mylenkyy
Quintagroup, 2008
What we'll talk about
Testing intro
unittest
doctest
zope.testing
Zope Test Cases
Plone Test Cases
Testing intro
Problem
Types of test
Unit tests
Integration tests
Functional tests
System tests
Testing and documentation
unittest
Author Steve Purcell
Actually is PyUnit, which is part of the Python 2.1 standard library
based on Erich Gamma's JUnit and Kent Beck's Smalltalk testing framework.
main = TestProgram(TP)(ready to use tests runner class)
unittest.py
TCTCTC
TestSuite(TS)TestCase(TC)TestResult(TR)
TestLoader(TL)[test case/suite finder]TestRunner(TR)
TestSuite TestCase
Output results
unittest: TestCase
testMethodName
result
fail*/assert*
(failUnless|assert)Raises
run/debug
__call__
run(result)
result.startTest()result.stopTest()testMethod()setUp()tearDown()
debug
unittest: module members
TestSuite
_test (addTest, addTests)
run/debug (__call__)
TestLoader
define test method prefix ['test']
sort test method function [cmp]
Methods:
loadTestsFrom* [TestCase, Module, Name, Names]
getTestCaseNames -> use test method prefix for find test methods -> used for build TestCase instances
unittest: module members (cont.)
TextTestRunner
TestProgram
FunctionTestCase
TestResult
Help functions:
makeSuite,
findTestCase,
getTestCaseNames
unittest: TestSuite / TestCase
import unittest as ut
class WidgetTC(ut.TestCase): def setUp(self): ... def tearDown(self): ... def testDefaultSize(self): assertEqual(...) def testResize(self): self.failIf(...) def otherTest(self): self.assertRaises(...)
if __name__ == '__main__': # 1 # ut.main() #1b# ut.main(defaultTest='WidgetTC') #2,3# suite = ut.TestSuite() # 2 # suite.addTest(ut.makeSuite(WidgetTC)) # 3 # suite.addTest('WidgetTC('otherTest')) #2,3# runner = ut.TextTestRunner() #2,3# runner.run(sute)
TestSuite
_tests
WidgetTC("testDefaultSize")WidgetTC("testResize")unittest.makeSuite(WidgetTC)
unittest: command line
mytest.py----------------------------------------------import unittestclass WidgetTC(unittest.TestCase): ...if __name__ == '__main__': unittest.main()-----------------------------------------------$ python mytest.py..OK-------------------------------------------------$ python mytest.py WidgetTC.testDefaultSize WidgetTC.testResize..OK-------------------------------------------------$ python mytest.py -vtestDefaultSize (__main__.WidgetTC) ... oktestResize (__main__.WidgetTC) ... ok...OK
doctest
Authors: Jim Fulton, Edward Loper
part of the Python standard library since version 2.1.
import types, mymodule, doctestdef hasInt(*args): """ Test is integer value present in args. >>> hasInt("the string") False
>>> hasInt("the string", 1) True """ args = list(args) while args: if type(args.pop()) == types.IntType: return True return False
__test__ = {'My module test' : mymodule, 'My string test' : >>>1==1True}if __name__ == '__main__': doctest.testmod()
doctest: bases
Python shell with explanations
Docstrings
Separate file
__test__ in module
doctest: testmod/testfile
testmod()
m=None
globs=None
optionflags=0
verbose=None, report=True, raise_on_error=False
testfile(filename)
module_relative=True, package=None
parser=DocTestParser()
same to testmod
run_docstring_examples(f, globs)
compileflags=None
doctest: Option flags
COMPARISON_FLAGS
DONT_ACCEPT_TRUE_FOR_1, DONT_ACCEPT_BLANKLINE, NORMALIZE_WHITESPACE, ELLIPSIS, IGNORE_EXCEPTION_DETAIL
REPORTING_FLAGS
REPORT_ONLY_FIRST_FAILURE, REPORT_*DIFF
`want` strings markers
BLANKLINE_MARKER='', ELLIPSIS_MARKER = '...'
Test ELLIPSIS option >>> range(100) #doctest:+ELLIPSIS [0, ..., 99]
>>> range(100) [0, ..., 99]
import doctest>>> range(100) [0, ..., 99]doctest.testmod( optionflags=doctest.ELLIPSIS)
doctest: Unittest Support
DocTestSuite
Common options: module, globs, extraglobs, test_finder
**options: setUp, tearDown, globs, optionflags
DocFileTest(path)
module_relative=True, package=None
set_unittest_reportflags. Only reporting
>>> range(100)\n[0, ..., 99]import doctest, unittestif __name__ == __main__:suite = unittest.TestSuite() testrunner = unittest.TextTestRunner() testrunner.run(doctest.DocTestSuite(optionflags=doctest.ELLIPSIS)) #testrunner.run(doctest.DocTestSuite())
doctest: Internal structure
objectDocTest
ExampleExampleExampleresultDocTestFinderDocTestRunner
zope.testing
testrunner for run automated tests
primary feature - it finds tests in directory trees
highly customizable
Test filtering
Organization of tests into levels and layers
Reporting
Analysis of test execution
setUp
tearDownsetUp
tearDown
TestCaseTestCaseTestCasezope.testing: Lyaers
Minimize the number of invocations
TestCase/TestSuite associate with layer
Classes with setUp and tearDown class methods
Nested Layers
testSetUp/testTearDown
-l --layer=
Unit layer (-u) / not unit (-f)
zope.testing: Lyaers (cont)
class BaseLayer: @classmethod def setUp(cls): Layer setup @classmethod def tearDown(cls): Layer teardown @classmethod def testSetUp(cls): Before each test setup @classmethod def testTearDown(cls): After each test teardown
class MyTestCase(TestCase): layer = NestedLayer def setUp(self): pass
def tearDown(self): pass
class NestedLayer(BaseLayer): @classmethod def setUp(cls): Layer setup @classmethod def tearDown(cls): Layer teardown
testrunner.py --path', directory_with_tests --layer 112 --layer Unit'.split
zope.testing: Levels
Additional filter alow run tests for specific level
TestCase/TestInteger attribute 'level' integer >0
Test runner can be configured to only run tests at a specific level or below by default.
Additional filter alow run tests for specific level
TestCase/TestInteger attribute 'level' integer >0
Test runner can be configured to only run tests at a specific level or below by default.
If no level -> assumed level 1
by default, only tests at level 1
--at-level (-a) / --all
TestCaseTestCaseTestCaseTestCaseTestCaseTestCase
Level 1
Level 2
TestCaseTestCaseTestCaseLevel - 3
zope.testing: Test selection
Search for
Package (-s, --package, --dir)
Module (-m, --module)
Test within the module (-t, --test )
layer (-l, --level) & level (-a, --at-level / --all )
--tests-pattern (--tests-pattern ^tests$ )
--test-suite ('test_suite' by default)
Module & Test can be re.expr, positional args
zope.testing: options (cont)
Where search for tests
--path
--test-path / --package-path --> not add to sys.path
--progress (-p). -v (with test descriptions)
--coverage= - where put coverage reports
--profile
--repeat
--verbose (-v) / --quiet (-q)
zope.testing: test.py script
Wrapper around zope.testing.testrunner
Extends testrunner with options:
--config-file
--nowarnings
Prepare default options list for call with testrunner:
--path = INSTANCE_HOME/python/lib
--package-path products Products
call testrunner.run
zope.testing: examples
$ZH/bin/test.py --config-file=$IH/etc/zope.conf \
--path=~/Plone/lib/python \
--package-path ~/Plone/Products Products \
-s Products.CMFQuickInstallerTool
$INSTANCE_HOME/bin/zopectl test \
-s Products.CMFQuickInstallerTool
ZopeTestCase(ZTC)
Author : Stefan H. Holek
ZTC Goals
Simplify distribute tests with Zope products.
Be as close to real Zope as possible.
Be as simple to use as unittest.
Decisions
Base ZTC on Testing and improve on it
Provide a batteries included Zope test sandbox
Support for testing Zope security.
ZTC: framework.py vs test.py
framework.py now depricated
bin/test.py config-file=.../zope.conf ...
BUT:
Supports custom_zodb.py in the tests directory
Allows to connect to a running ZEO server
import osfrom ZODB.DemoStorage import DemoStoragefrom ZODB.FileStorage import FileStoragedb = os.path.join('..', '..', '..', 'var', 'Data.fs')db = os.path.abspath(db)Storage = DemoStorage(base=FileStorage(db, read_only=1))
ZTC: ZopeTestCase.py
ZopeTestCase class
ZopeTestCase sets up a default fixture
Handles opening and closing of ZODB con.
Handles transactions
Provides a REQUEST object
API to modify the test users credentials
ZTC: Entrypoints
setUp(self)try: self.beforeSetUp() self.app = self._app() self._setup() self.afterSetUp()except: self._clear() raise
tearDown(self)try: self.beforeTearDown() self._clear(1)except: self._clear() raise
Zope.APP
Opens a ZODB connection Request.__of__(app)
Before ALL
ZTC Folder, UserFolder, User, login
After Fixture created
ConnectionRegistry
Before delete folderfrom self.app
After folder deleteBefore close connection to ZODBbeforeClose()
afterClear()
After ALL
ZTC: Class diagram
ZTC: Writing Tests
Create a test case class derived from ZopeTestCase.ZopeTestCase
Override afterSetUp() / tearDown() to add the objects you want to test, clearing data
Write one or more tests exercising these objects
Define test_suite object, which return unittest.TestSuite object
ZTC: Example
import unittest
from Testing import ZopeTestCase
ZopeTestCase.installProduct(SomeProduct)
class MyTest(ZopeTestCase.ZopeTestCase):
def afterSetUp(self):
self.folder.addDTMLMethod(foo)
def testFoo(self):
assert hasattr(self.folder, foo)
def test_suite():
return unittest.TestSuite(
[unittest.makeSuite(MyTest),] )
PortalTestCase
Almost ZopeTestCase
portal object (self.portal)
user folder (UF) inside the portal
portal object must create in Subclasses
getPortal() returns a usable portal object
Defaults:
user with role 'Member' inside the UF
default user's memberarea (self.folder)
default user is logged in
PortalTestCase (cont)
portal = 'portal'
setUp(self)try: self.beforeSetUp() self.app = self._app() self.portal = self._portal() self._setup() self.afterSetUp()except: self._clear() raise
_portal(self)return self.getPortal()
getPortal(self)return getattr(self.app, poratl)
PloneTestCase(PTC)
PloneTestCase class
Usefull methods:
hasProduct. installProduct
hasPackage, installPackage
setupPloneSite(products, extension_profiles)
Constants:
portal_*, default_*
PLONE2.x, PLONE3.x, PLONE4.x
PTC: PloneTestCase (cont)
Plone installs in setup.py module
ZCMLLayer, PloneSiteLayer(ZCML) layers
onsetup, onteardown functions.
Extend PortalTestCase security with methods:
setGroups, loginAsPortalOwner
PTC: PloneTestCase example
import os, sysif __name__ == '__main__': execfile(os.path.join(sys.path[0], 'framework.py'))
from Products.PloneTestCase import PloneTestCase
PloneTestCase.setupPloneSite()
class TestDocument(PloneTestCase.PloneTestCase):
def afterSetUp(self): ...
def testAddDocument(self): self.failUnless(...)
def test_suite(): ... return suite
if __name__ == '__main__': framework()
Resources
Sources ;)
http://plone.org/documentation/tutorial/testing
http://www.zope.org/Members/shh/ZopeTestCaseWiki
http://pypi.python.org/pypi/zope.testing/3.6.0
http://agiletesting.blogspot.com
http://pyunit.sourceforge.net
http://svn.plone.org/svn/collective/examples/example.tests/trunk
Click to edit the title text format