Author: hpk Date: Wed Feb 3 12:31:50 2010 New Revision: 71077 Added: py/extradoc/talk/pycon-us-2010/pytest-introduction/ - copied from r70384, py/extradoc/talk/pycon-us-2009/pytest-introduction/ py/extradoc/talk/pycon-us-2010/pytest-introduction/1/ py/extradoc/talk/pycon-us-2010/pytest-introduction/1/myscan/ py/extradoc/talk/pycon-us-2010/pytest-introduction/1/myscan/__init__.py py/extradoc/talk/pycon-us-2010/pytest-introduction/1/myscan/config.py py/extradoc/talk/pycon-us-2010/pytest-introduction/1/myscan/test/ py/extradoc/talk/pycon-us-2010/pytest-introduction/1/myscan/test/__init__.py py/extradoc/talk/pycon-us-2010/pytest-introduction/1/myscan/test/test_config.py py/extradoc/talk/pycon-us-2010/pytest-introduction/author.latex py/extradoc/talk/pycon-us-2010/pytest-introduction/beamerdefs.txt py/extradoc/talk/pycon-us-2010/pytest-introduction/makepdf (contents, props changed) py/extradoc/talk/pycon-us-2010/pytest-introduction/pytest-basic.txt py/extradoc/talk/pycon-us-2010/pytest-introduction/rst2beamer.py (contents, props changed) py/extradoc/talk/pycon-us-2010/pytest-introduction/title.latex Log: initial tutorial draft, work-in-progress
Added: py/extradoc/talk/pycon-us-2010/pytest-introduction/1/myscan/__init__.py ============================================================================== --- (empty file) +++ py/extradoc/talk/pycon-us-2010/pytest-introduction/1/myscan/__init__.py Wed Feb 3 12:31:50 2010 @@ -0,0 +1 @@ +# Added: py/extradoc/talk/pycon-us-2010/pytest-introduction/1/myscan/config.py ============================================================================== --- (empty file) +++ py/extradoc/talk/pycon-us-2010/pytest-introduction/1/myscan/config.py Wed Feb 3 12:31:50 2010 @@ -0,0 +1,10 @@ +from ConfigParser import ConfigParser + +class Config: + def __init__(self, path): + f = open(path) + parser = ConfigParser() + parser.readfp(f) + f.close() + parser.read(path) + self.extensions = parser.get("myapp", 'extensions').split() Added: py/extradoc/talk/pycon-us-2010/pytest-introduction/1/myscan/test/__init__.py ============================================================================== --- (empty file) +++ py/extradoc/talk/pycon-us-2010/pytest-introduction/1/myscan/test/__init__.py Wed Feb 3 12:31:50 2010 @@ -0,0 +1 @@ +# Added: py/extradoc/talk/pycon-us-2010/pytest-introduction/1/myscan/test/test_config.py ============================================================================== --- (empty file) +++ py/extradoc/talk/pycon-us-2010/pytest-introduction/1/myscan/test/test_config.py Wed Feb 3 12:31:50 2010 @@ -0,0 +1,18 @@ + +from py.test import raises +from myscan.config import Config +import os + +def test_config_extensions(): + import tempfile + tmpdir = tempfile.mkdtemp() + path = os.path.join(tmpdir, 'config.ini') + f = open(path, 'w') + f.write("[myapp]\n") + f.write("extensions = .txt .rst") + f.close() + config = Config(path) + assert config.extensions == ['.txt', '.rst'] + +def test_parsefile_file_not_exists(): + raises(IOError, "Config('file_not_exists')") Added: py/extradoc/talk/pycon-us-2010/pytest-introduction/author.latex ============================================================================== --- (empty file) +++ py/extradoc/talk/pycon-us-2010/pytest-introduction/author.latex Wed Feb 3 12:31:50 2010 @@ -0,0 +1,7 @@ +\definecolor{rrblitbackground}{rgb}{0.0, 0.0, 0.0} + +\title[py.test basic testing tutorial] {pytest basic testing tutorial} +\author[H. Krekel]{Holger Krekel \\ http://merlinux.eu} + +\institute[PyCon US 2010, Atlanta]{PyCon US 2010, Atlanta} +\date{Feb 18th, 2010} Added: py/extradoc/talk/pycon-us-2010/pytest-introduction/beamerdefs.txt ============================================================================== --- (empty file) +++ py/extradoc/talk/pycon-us-2010/pytest-introduction/beamerdefs.txt Wed Feb 3 12:31:50 2010 @@ -0,0 +1,77 @@ +.. colors +.. =========================== + +.. role:: green +.. role:: red + + +.. general useful commands +.. =========================== + +.. |pause| raw:: latex + + \pause + +.. |small| raw:: latex + + {\small + +.. |end_small| raw:: latex + + } + + +.. closed bracket +.. =========================== + +.. |>| raw:: latex + + } + + +.. example block +.. =========================== + +.. |example<| raw:: latex + + \begin{exampleblock}{ + + +.. |end_example| raw:: latex + + \end{exampleblock} + + + +.. alert block +.. =========================== + +.. |alert<| raw:: latex + + \begin{alertblock}{ + + +.. |end_alert| raw:: latex + + \end{alertblock} + + + +.. columns +.. =========================== + +.. |column1| raw:: latex + + \begin{columns} + \begin{column}{0.45\textwidth} + +.. |column2| raw:: latex + + \end{column} + \begin{column}{0.45\textwidth} + + +.. |end_columns| raw:: latex + + \end{column} + \end{columns} Added: py/extradoc/talk/pycon-us-2010/pytest-introduction/makepdf ============================================================================== --- (empty file) +++ py/extradoc/talk/pycon-us-2010/pytest-introduction/makepdf Wed Feb 3 12:31:50 2010 @@ -0,0 +1,14 @@ +#!/bin/bash + +# you can find rst2beamer.py here: +# http://codespeak.net/svn/user/antocuni/bin/rst2beamer.py + +# WARNING: to work, it needs this patch for docutils +# https://sourceforge.net/tracker/?func=detail&atid=422032&aid=1459707&group_id=38414 + +BASE=pytest-basic +python rst2beamer.py --stylesheet=stylesheet.latex --documentoptions=14pt $BASE.txt $BASE.latex || exit +sed 's/\\date{}/\\input{author.latex}/' $BASE.latex >tmpfile || exit +sed 's/\\maketitle/\\input{title.latex}/' tmpfile >$BASE.latex || exit +pdflatex $BASE.latex || exit + Added: py/extradoc/talk/pycon-us-2010/pytest-introduction/pytest-basic.txt ============================================================================== --- (empty file) +++ py/extradoc/talk/pycon-us-2010/pytest-introduction/pytest-basic.txt Wed Feb 3 12:31:50 2010 @@ -0,0 +1,484 @@ +.. include:: beamerdefs.txt +.. include:: <s5defs.txt> + +================================================================= +Rapid testing with py.test +================================================================= + +these slides +==================== + +If you have time before the tutorial starts, please make sure +you have installed the latest pylib. You need either: + +- ``setuptools``: http://pypi.python.org/pypi/setuptools +- ``distribute``: http://pypi.python.org/pypi/distribute + +and can then type:: + + easy_install py # or + pip install py + +A copy of this presentation & exercises: + +http://codespeak.net/svn/py/extradoc/talk/pycon-us-2010/pytest-introduction/pytest-introduction.zip + +me +== + +Holger Krekel <hol...@merlinux.eu> + +- developer of py.test and execnet +- founded the PyPy project +- Python since around 2000 +- Test-driven development since 2001 +- operates a small company doing open + source, Python and test-oriented consulting + +you +=== + +What is your background? + +.. class:: handout + + Python background + Testing background + python testing libraries: unittest, nose, py.test... + +why automated testing? +================================== + +- to allow for later changes +- to raise confidence that code works +- to specify and document behaviour +- collaborative and faster development cycles + +Developer oriented automated tests +======================================== + +* unittest: units react well to input. +* integration: components co-operate nicely +* functional: code changes work out in user environments + +unittest +============ + +assert that functions and classes behave as expected + +.. image:: img/small.png + :align: center + :scale: 70 + + +integration +============== + +assert units/components co-operate nicely + +.. image:: img/medium.png + :align: center + :scale: 70 + + +functional / system +======================== + +things work in user target environment + +.. image:: img/large.png + :align: center + :scale: 70 + +The test tool question +======================================== + +what is the job of automated testing tools? + + +my current answer +======================================== + +* verify code changes work out +* be helpful when tests fail + +If failures are not helpful ... +======================================== + +improve the test tool or + +write more or write different tests + +py.test basics +============================================================================ + +.. image:: img/new_color_in_dark_old_city_by_marikaz.jpg + :scale: 100 + :align: left + +http://marikaz.deviantart.com/ CC 3.0 AN-ND + +py.test fundamental features +=============================== + +- cross-project testing tool +- no-boilerplate test code +- useful information when a test fails +- deep extensibility +- distribute tests to multiple hosts + +cross-project test tool +=========================== + +- tests are run via ``py.test`` command line tool. + +- project specific ``conftest.py`` files + +- testing starts from files/dirs or current dir + +examples:: + + py.test test_file.py + py.test path/to/tests + +A Typical Python test layout +========================================== +:: + + mypkg/__init__.py + ... + mypkg/tests/test_module.py + ... + +example invocation:: + + py.test mypkg + +Another typical test layout +========================================== +:: + + mypkg/__init__.py + ... + test/test_module.py + +example invocations:: + + py.test test + py.test # starts discovery in cwd + +mind the `tests/__init__.py` files +========================================== + +- test files are imported as normal python modules +- make test directories a package to disambiguate + +note: first non-``__init__.py`` dir is inserted into sys.path + +automatic test discovery +=================================== + +py.test walks over the filesystem and: + +- discovers ``test_*.py`` test files +- discovers ``test_`` functions and ``Test`` classes + +**automatic discovery avoids boilerplate** + +no boilerplate python test code +================================= + +example test functions/methods:: + + def test_something(): + x = 3 + assert x == 4 + + class TestSomething: + def test_something(self): + x = 1 + assert x == 5 + +assert introspection +======================= + +:: + + def test_assert_introspection(): + # with unittest.py + assert x # assertTrue() + assert x == 1 # assertEqual(x, 1) + assert x != 2 # assertNotEqual(x, 2) + assert not x # assertFalse(x) + + +assertin expected exceptions +================================ + +:: + + import py + + def test_raises_one(): + py.test.raises(ValueError, int, 'foo') + + def test_raises_two(): + py.test.raises(ValueError, "int('foo')") + +Failure / Traceback Demo +=========================== + +interactive demo: ``py.test failure_demo.py`` + + +print() debugging +================= + +:: + + def test_something1(): + print "Useful debugging information." + assert False + +output captured per function run, only shown on failure. + +some important options +======================== + +see also ``py.test -h``: + +- -s disable catching of stdout/stderr +- -x exit instantly on first failure +- -k run tests whose names contain a keyword +- -l show locals in tracebacks. +- --pdb start Python debugger on errors +- --tb/fulltrace - control traceback generation. + +Getting Started ... +============================= + +Installation: + +``easy_install -U py``, ``pip install py`` or: + + - hg clone https://bitbucket.org/hpk42/py-trunk/ + - run "python setup.py" with "install" or "develop" + +Notes: + + http://pylib.org/install.html + +"myscan": Exercises of this tutorial +===================================== + +we'll step-by-step build up a ``myscan`` project with tests. + +in the process you learn how to use py.test conveniently. + + +sketching our "myscan" project +================================ + +Application Objects: + +- Config object: read configuration from an .ini file +- Scanner object: parse files for lines starting with a prefix + +Tests will be about: + +- config file parsing +- using the scanner object and its method(s) + +Starting Exercise +=========================== + +- create ``myscan/test/test_config.py`` (plus ``__init__.py`` files) +- create ``myscan/config.py`` +- write a test that instantiates ``myscan.config.Config()`` + and checks that ``extensions`` is initialized +- run ``py.test mypkg`` + +Helping Notes +============================= + +test setup / fixture basics +==================================================== + +a test fixture: + +- sets up objects or apps for testing +- provides test code with "base" app objects +- py.test supports xUnit/unittest.py/nosetests style setup + +test functions and funcargs +==================================================== + +**funcargs** are a unique py.test feature: + +- a mechanism for providing test "base" values +- can easily depend on command line options +- separates test code from test setup +- naturally extend towards test parametrization + +let's look a bit more at the motivation ... + +Typical test function - viewed abstractly +========================================== +:: + + from mypkg.mod import SomeClass + def test_method(): + inst1 = SomeClass("somevalue") + ... + assert inst1.method() == "ok" + + +observations and the fixture question +========================================== + +* the test wants to check a method call result +* ``SomeClass`` base value Instantiation mixes with test code +* the ``mypkg.mod.SomeClass`` reference may change + +What if multiple test functions need a similar instance? + +old-style strategy: xUnit-style fixtures +========================================== + +:: + + from mypkg.mod import SomeClass + import unittest + class TestGroup(unittest.TestCase): + def setUp(self): + self.inst1 = SomeClass("somevalue") + + def test_something(self): + ... use self.inst1 ... + assert self.inst1.method() == "ok" + + +observations / notes +========================================== + +* unittest-runner automatically invokes ``self.setUp()`` + for each test function invocation. +* test value for Instantiation mixes with test module code +* ``mypkg.mod.SomeClass`` reference may change +* **multiple methods can reuse the same setup** +* **test functions group by setup code** + +meet "funcargs" - test function arguments +========================================== + +simple funcarg test code example:: + + def test_something(inst1): + assert inst1.method() == "ok" + +observations +============== + +* test function "requests" arguments it needs +* functions/methods re-use same funcarg setup +* grouping in test classes independent of setup + +How to provide the function argument? +========================================== +:: + + #./conftest.py (or directly in test module) + + from mypkg.mod import SomeClass + def pytest_funcarg__inst1(request): + return SomeClass("somevalue") + +funcarg factory observations +=================================================== + +* discovered through naming convention +* loosely coupled, separated from test code +* will be called for each test function +* has one mypkg.mod.SomeClass reference + +Exercise +========================================== + +* write a package "mypkg" +* add mypkg/__init__.py and mypkg/test_url.py +* add a ``def test_path(url)`` function +* write a ``pytest_funcarg__url`` factory in mypkg/conftest.py +* run your test + +(Bonus: play with wrong funcarg names) + +application scenario setup (30) +=================================================== + +- + +exercise: separate your test setup and test code and +implement the "mysetup" testing pattern + +step 1: use a "mysetup" +======================================== + +Let's write a simple test function living in a test file +``test_sample.py`` that uses a ``mysetup`` funcarg for accessing test +specific setup. + +.. sourcecode:: python + + # ./test_sample.py + def test_answer(mysetup): + app = mysetup.myapp() + answer = app.question() + assert answer == 42 + + +marking tests (15) +=================================================== + +interactive lecture: +- marking tests for skip and xfail +- marking classes and modules +- selectively running tests + +hooks and plugins (15) +=================================================== + +interactive lecture: +- conftest plugins +- plugin discovery +- pytest hook functions + +new command line option (20) +=================================================== + +exercise: +- add a new cmdline option for the "mysetup" setup object +- skip test depending on a cmdline option + +coverage testing (20) +=================================================== + +- figleaf and coverage tools +- installing figleaf or coverage +- exercise: get html coverage for your code + +overview on advanced usages (10) +=================================================== + +interactive lecture: +- looponfailing +- distributed testing (part II) +- generative tests (part II) +- doctests (part II) +- javascript testing + +conclusion (10 mins) +=================================================== + +- summary +- feedback session + Added: py/extradoc/talk/pycon-us-2010/pytest-introduction/rst2beamer.py ============================================================================== --- (empty file) +++ py/extradoc/talk/pycon-us-2010/pytest-introduction/rst2beamer.py Wed Feb 3 12:31:50 2010 @@ -0,0 +1,170 @@ +#!/usr/bin/env python +# encoding: utf-8 +""" +A docutils script converting restructured text into Beamer-flavoured LaTeX. + +Beamer is a LaTeX document class for presentations. Via this script, ReST can +be used to prepare slides. It can be called:: + + rst2beamer.py infile.txt > outfile.tex + +where ``infile.tex`` contains the produced Beamer LaTeX. + +See <http:www.agapow.net/programming/python/rst2beamer> for more details. + +""" +# TODO: modifications for handout sections? +# TOOD: sections and subsections? +# TODO: enable beamer themes? +# TODO: convert document metadata to front page fields? +# TODO: toc-conversion? +# TODO: fix descriptions + +# Unless otherwise stated, created by P-M Agapow on 2007-08-21 +# and open for academic & non-commercial use and modification . + +__docformat__ = 'restructuredtext en' +__author__ = "Paul-Michael Agapow <aga...@bbsrc.ac.uk>" +__version__ = "0.2" + + +### IMPORTS ### + +import locale +from docutils.core import publish_cmdline, default_description +from docutils.writers.latex2e import Writer as Latex2eWriter +from docutils.writers.latex2e import LaTeXTranslator, DocumentClass +from docutils import nodes + +## CONSTANTS & DEFINES: ### + +BEAMER_SPEC = ( + 'Beamer options', + 'These are derived almost entirely from the LaTeX2e options', + tuple ( + [ + ( + 'Specify theme.', + ['--theme'], + {'default': '', } + ), + ( + 'Specify document options. Multiple options can be given, ' + 'separated by commas. Default is "10pt,a4paper".', + ['--documentoptions'], + {'default': '', } + ), + ] + list (Latex2eWriter.settings_spec[2][2:]) + ), +) + +BEAMER_DEFAULTS = { + 'output_encoding': 'latin-1', + 'documentclass': 'beamer', +} + + +### IMPLEMENTATION ### + +try: + locale.setlocale (locale.LC_ALL, '') +except: + pass + +class BeamerTranslator (LaTeXTranslator): + """ + A converter for docutils elements to beamer-flavoured latex. + """ + + def __init__ (self, document): + LaTeXTranslator.__init__ (self, document) + self.head_prefix = [x for x in self.head_prefix if ('{typearea}' not in x)] + hyperref_posn = [i for i in range (len (self.head_prefix)) if ('{hyperref}' in self.head_prefix[i])] + self.head_prefix[hyperref_posn[0]] = '\\usepackage{hyperref}\n' + self.head_prefix.extend ([ + '\\definecolor{rrblitbackground}{rgb}{0.55, 0.3, 0.1}\n', + '\\newenvironment{rtbliteral}{\n', + '\\begin{ttfamily}\n', + '\\color{rrblitbackground}\n', + '}{\n', + '\\end{ttfamily}\n', + '}\n', + ]) + # this fixes the hardcoded section titles in docutils 0.4 + self.d_class = DocumentClass ('article') + + def begin_frametag (self): + return '\\begin{frame}\n' + + def end_frametag (self): + return '\\end{frame}\n' + + def visit_section (self, node): + if (self.section_level == 0): + self.body.append (self.begin_frametag()) + LaTeXTranslator.visit_section (self, node) + + def depart_section (self, node): + # Remove counter for potential subsections: + LaTeXTranslator.depart_section (self, node) + if (self.section_level == 0): + self.body.append (self.end_frametag()) + + def visit_title (self, node): + if (self.section_level == 1): + self.body.append ('\\frametitle{%s}\n\n' % self.encode(node.astext())) + raise nodes.SkipNode + else: + LaTeXTranslator.visit_title (self, node) + + def depart_title (self, node): + if (self.section_level != 1): + LaTeXTranslator.depart_title (self, node) + + def visit_literal_block(self, node): + if not self.active_table.is_open(): + self.body.append('\n\n\\smallskip\n\\begin{rtbliteral}\n') + self.context.append('\\end{rtbliteral}\n\\smallskip\n\n') + else: + self.body.append('\n') + self.context.append('\n') + if (self.settings.use_verbatim_when_possible and (len(node) == 1) + # in case of a parsed-literal containing just a "**bold**" word: + and isinstance(node[0], nodes.Text)): + self.verbatim = 1 + self.body.append('\\begin{verbatim}\n') + else: + self.literal_block = 1 + self.insert_none_breaking_blanks = 1 + + def depart_literal_block(self, node): + if self.verbatim: + self.body.append('\n\\end{verbatim}\n') + self.verbatim = 0 + else: + self.body.append('\n') + self.insert_none_breaking_blanks = 0 + self.literal_block = 0 + self.body.append(self.context.pop()) + + +class BeamerWriter (Latex2eWriter): + """ + A docutils writer that modifies the translator and settings for beamer. + """ + settings_spec = BEAMER_SPEC + settings_defaults = BEAMER_DEFAULTS + + def __init__(self): + Latex2eWriter.__init__(self) + self.translator_class = BeamerTranslator + + +if __name__ == '__main__': + description = ( + "Generates Beamer-flavoured LaTeX for PDF-based presentations." + default_description) + publish_cmdline (writer=BeamerWriter(), description=description) + + +### END ###################################################################### + Added: py/extradoc/talk/pycon-us-2010/pytest-introduction/title.latex ============================================================================== --- (empty file) +++ py/extradoc/talk/pycon-us-2010/pytest-introduction/title.latex Wed Feb 3 12:31:50 2010 @@ -0,0 +1,7 @@ +\begin{titlepage} +\begin{figure}[h] +\includegraphics[width=64px,height=64px]{img/merlinux-logo.jpg} +\qquad +\includegraphics[width=80px]{img/py-web.png} +\end{figure} +\end{titlepage} _______________________________________________ py-svn mailing list py-svn@codespeak.net http://codespeak.net/mailman/listinfo/py-svn