==================== Functional doc tests ==================== Doctests are a way to write tests while documenting the thing that is tested at the same time. As an example, this file both documents functional doc tests *and* tests them. Doctests look like regular interactive interpreter sessions. That makes them very easy to create. Doctests can either occur in an object's or method's docstring or in a separate file. Use either ``DocTestSuite`` or ``DocFileSuite`` in these cases. Creating functional doctests ---------------------------- Creating functional doctests is just as easy. Obviously, you cannot simply use an interpreter shell for the initial test creation. Instead, you can use the `tcpwatch` program to record browser sessions and turn them into tests: 1. Start out with a clean ZODB database. - Create a folder named `test_folder_1_` in the root folder. - Create a user in the root user folder called `test_user_1_` with the password `secret`. - Create a role `test_role_1_` and grant the role to the test user. Grant the permissions 'Access contents information' and 'View' to the role. 2. Install tcpwatch. You can get a recent version from Zope CVS: http://cvs.zope.org/Packages/tcpwatch/ 3. Create a temporary directory to record tcpwatch output. 4. Run tcpwatch using: tcpwatch.py -L 8081:8080 -s -r tmpdir (the ports are the listening port and forwarded-to port; the second port must match the Zope configuration) 5. In a browser, connect to the listening port and do whatever needs to be recorded. 6. Shut down tcpwatch. 7. Run the script at Zope/lib/python/Testing/ZopeTestCase/doctest/dochttp.py python2.3 dochttp.py tmpdir > .../mytest.txt 8. Edit the generated text file to add explanations and elide uninteresting portions of the output. 9. In a functional test module (usually ftests.py), import ``FunctionalDocFileSuite`` and instantiate it, passing the name of the text file containing the test. For example: import os, sys if __name__ == '__main__': execfile(os.path.join(sys.path[0], 'framework.py')) from unittest import TestSuite from Testing.ZopeTestCase import FunctionalDocFileSuite def test_suite(): return TestSuite(( FunctionalDocFileSuite('FunctionalDocTest.txt'), )) if __name__ == '__main__': framework() Examples -------- Test Publish Document >>> print http(r""" ... GET /test_folder_1_/index_html HTTP/1.1 ... """, handle_errors=False) HTTP/1.1 200 OK Content-Length: 5 Content-Type: text/plain index Test Publish Script >>> print http(r""" ... GET /test_folder_1_/script HTTP/1.1 ... """, handle_errors=False) HTTP/1.1 200 OK Content-Length: 1 Content-Type: text/plain 1 Test Publish Script with Argument >>> print http(r""" ... GET /test_folder_1_/script?a:int=2 HTTP/1.1 ... """, handle_errors=False) HTTP/1.1 200 OK Content-Length: 1 Content-Type: text/plain 3 Test Server Error >>> print http(r""" ... GET /test_folder_1_/script?a=2 HTTP/1.1 ... """, handle_errors=False) HTTP/1.1 500 Internal Server Error ...Content-Type: text/html...exceptions.TypeError... Test Unauthorized >>> self.folder.index_html.manage_permission('View', ['Owner']) >>> print http(r""" ... GET /test_folder_1_/index_html HTTP/1.1 ... """, handle_errors=False) HTTP/1.1 401 Unauthorized ... Test Basic Authentication >>> from AccessControl.Permissions import manage_properties >>> self.setPermissions([manage_properties]) >>> print http(r""" ... GET /test_folder_1_/index_html/change_title?title=Foo HTTP/1.1 ... Authorization: Basic %s ... """ % user_auth, handle_errors=False) HTTP/1.1 200 OK Content-Length: 0 ... >>> self.folder.index_html.title_or_id() 'Foo' Test passing in non-base64-encoded login/pass >>> from Testing.ZopeTestCase import user_name, user_password >>> print http(r""" ... GET /test_folder_1_/index_html/change_title?title=Baz HTTP/1.1 ... Authorization: Basic %s:%s ... """ % (user_name, user_password), handle_errors=False) HTTP/1.1 200 OK Content-Length: 0 ... >>> self.folder.index_html.title_or_id() 'Baz'