Author: tziade Date: Fri Mar 10 18:05:25 2006 New Revision: 2571 Added: cookbook/trunk/recipe48.fr.tex cookbook/trunk/recipe49.fr.tex cookbook/trunk/recipe50.fr.tex cookbook/trunk/recipe51.fr.tex cookbook/trunk/tests.txt (contents, props changed) cookbook/trunk/textest.py (contents, props changed) Modified: cookbook/trunk/macros.tex cookbook/trunk/recipe7.fr.tex cookbook/trunk/recipe_list.txt cookbook/trunk/tests.py Log: save point 'veauville' commit, before i forget
Modified: cookbook/trunk/macros.tex ============================================================================== --- cookbook/trunk/macros.tex (original) +++ cookbook/trunk/macros.tex Fri Mar 10 18:05:25 2006 @@ -12,8 +12,10 @@ \newenvironment{problem} { +\emph{\large{Probl�me}} +\begin{quote} } -{} +{\end{quote}} \newenvironment{solution} { @@ -25,3 +27,28 @@ \newcommand{\translator}[1]{ } + +\newcommand{\reviewer}[1]{ +} + + +\newcommand{\code}[1]{ +\url{#1} +} + +\newcommand{\codetitle}[1] { +\vspace{4pt} +\noindent\emph{\underline{#1}} +} + +\newenvironment{codenotes} +{\hrule +\begin{list}{$\triangleright$}{\setlength{\leftmargin}{1em}} +} +{\end{list}} + +\newcommand{\comment}[1]{ +\begin{comment} +#1 +\end{comment} +} Added: cookbook/trunk/recipe48.fr.tex ============================================================================== --- (empty file) +++ cookbook/trunk/recipe48.fr.tex Fri Mar 10 18:05:25 2006 @@ -0,0 +1,105 @@ +\documentclass{book} +\pagestyle{headings} +\include{macros} +\status{draft} +\author{Tarek Ziad�} + +\begin{document} + +\chapter*{Ecrire du reSTructuredText pour la documentation et les doctests} + +\begin{problem} +L'ensemble de la documentation des paquets de Zope est r�alis�e au format +reSTructuredText, ou reST, qui est une �volution du StructuredText. Ce format +fourni une structure simple, qui n'alourdit pas le texte, contrairement � +LaTeX, et peut �tre lu directement. Des outils permettent ensuite de manipuler +ce contenu pour le transformer en HTML, LaTeX, XML ou PDF. + +Cette recette est une \textit{cheatsheet} minimale, qui permet d'�crire des +doctests destin�s � des paquets Zope. +\end{problem} + +\begin{solution} +\section*{Structurer le fichier} +Pour organiser un fichier en section, sous-section, sous-sous-section, etc., +il suffit de souligner le titre de la section avec un caract�re dans l'ensemble: +\code{\/-=} ** a v�rifier **. A chaque section, si un nouveau caract�re est +utilis�, reST l'associe au niveau donn� pour le reste du document. + +\codetitle{Exemple de structure reST:} +\begin{verbatim} +Titre +===== + +Ok, donc j'ai deux sections. Profitez-en. + +Section 1 +~~~~~~~~~ + +Le titre est un frimeur. j'en parle dans une sous-section. + +Sous-Section 1 +-------------- + +Je suis charg� par ma section de casser du sucre sur le dos +de Titre, mais je n'en ferais rien, je vise une promotion. + +Section 2 +~~~~~~~~~ + +Calmons nous, le document est fini de toute mani�re... +\end{verbatim} + +\section*{Ins�rer des exemples de code} + +Ins�rer du code se fait en l'indentant d'au minimum 1 caract�re (en g�n�ral 2 +ou 4). Ce bloc doit �tre pr�c�d� du signe "::" et d'une ligne vide, puis +suivi d'une ligne vide. + +\codetitle{Insertion de code:} +\begin{verbatim} +Le module Math +============== + +Python dispose d'un module math, qui fourni une fonction pour les puissances:: + + >>> import math + >>> math.pow(56, 3) + 175616.0 + +Il y a aussi pi:: + + >>> math.pi + 3.1415926535897931 +\end{verbatim} +\begin{codenotes} +\item Zope 3 indente de deux caract�res, mais certains d�veloppeurs pr�f�rent +une indentation sur 4 caract�res, peut �tre pour �diter plus facilement +ces fichiers dans leur �diteur de code Python. +\end{codenotes} + +\section*{Ins�rer des liens et formatter le texte} + +\noindent reST permet aussi d'afficher du texte en italique, en gras. + +\codetitle{Gras et italique:} +\begin{verbatim} +Recette +======= + +Il n'y a absolument pas de **gras** dans les plats `italiens`. +\end{verbatim} + +\noindent La notation italique est utilis�e pour mettre en exergue un module +ou tout �l�ment de code dans le texte. La notation grasse est r�serv�e � la +mise en valeur de mots du texte. + +Pour les liens, AFINIR + +\section*{Bonnes pratiques en vrac} + +AFINIR + +\end{solution} + +\end{document} Added: cookbook/trunk/recipe49.fr.tex ============================================================================== --- (empty file) +++ cookbook/trunk/recipe49.fr.tex Fri Mar 10 18:05:25 2006 @@ -0,0 +1,21 @@ +\documentclass{book} +\pagestyle{headings} +\include{macros} +\status{draft} +\author{Tarek Ziad�} + +\begin{document} + +\chapter*{Utiliser zapi dans les tests} + +\begin{problem} +TODO +\end{problem} + +\begin{solution} +TODO +\end{solution} + +\end{document} + + Added: cookbook/trunk/recipe50.fr.tex ============================================================================== --- (empty file) +++ cookbook/trunk/recipe50.fr.tex Fri Mar 10 18:05:25 2006 @@ -0,0 +1,172 @@ +\documentclass{book} +\pagestyle{headings} +\include{macros} +\status{draft} +\author{Tarek Ziad�} + +\begin{document} + +\chapter*{Trouver le bon rythme entre codage, documentation, tests +fonctionnels et unitaires} + +\begin{problem} +Coder, tester, coder, tester, documenter, coder... + +Le rythme des activit�s de d�veloppement n'est pas �vident � �quiliber pour +un d�veloppeur novice. En fin de projet, tests et documentation passent souvent +� la trappe, victimes du stress du d�veloppeur, qui pr�f�re �courter ces �tapes +pour rendre son travail dans les temps, m�me si il sait pertinement qu'il le +payera par la suite. Ces p�riodes sont pourtant les plus importantes +pour le code (remaniement d'API, suppression de pans complets de code, etc..) + +Il est possible de limiter ces ph�nom�nes et gagner en efficacit�, par de +bonnes pratiques d�crites dans cette recette. Elles s'appliquent �videmment +� Zope, mais peuvent �tre utilis�es dans n'importe quel projet Python. +\end{problem} + +\begin{solution} +\section*{Comprendre les r�les du d�veloppeur} + +Le d�veloppeur, dans la quasi totalit� des projets, a trois activit�s: +\begin{itemize} +\item D�velopper; +\item documenter; +\item tester; +\end{itemize} + +La premi�re phase consiste bien s�r � cr�er le code. Un cycle de tests +fonctionnels plus pouss�s peut suivre cette phase, puis un retour vers +le d�veloppement est envisageable, pour des modifications, �volutions ou +d�bugguages. Ces cycles de vie logiciels sont plus ou moins �quivalents +dans toutes les m�thodologies existantes, comme le RUP*. Ce sujet d�passe +cependant le cadre de ce livre. + +\section*{Cr��r le code} + +Pour con�evoir une fonctionnalit�, un d�veloppeur r�cup�re un cahier des +charges, compos� de sp�cifications fonctionnelles, et parfois de sp�cifications +techniques. En se basant sur ce document, la cr�ation du code s'effectue en +trois �tapes: +\begin{itemize} +\item Transcrire le cahier des charges en fichier texte (doctest); +\item ins�rer des exemples de codes dans ce texte, qui r�pond aux besoins; +\item d�velopper le code sous-jacent aux exemples. +\end{itemize} + +\subsection*{Transcrire le cahier des charges en doctest} + +Transcrire en doctest les besoins exprim�s se fait en synth�sant au maximum le +cahier des charges, et en d�crivant la structure du paquet qui va �tre +d�velopp�. + +Prenons l'exemple d'un module en charge de r�cup�rer des flux rss pour les +stocker dans des objets Python persistents, puis les rendre affichables dans +l'application. Le d�veloppeur d�cide d'organiser son paquet en trois modules: +\begin{itemize} +\item \code{rssfetcher.py}: module en charge de la r�cup�ration des flux RSS; +\item \code{rssobject.py}: module en charge de la cr�ation et du stockage +des donn�es; +\item \code{rssview.py}: module en charge de l'affichage des donn�es. +\end{itemize} + +\noindent Il commence par �crire quatre fichiers doctests, qui expriment cette +structure: +\begin{itemize} +\item \code{README.txt} +\item \code{rssreader.txt} +\item \code{rssobject.txt} +\item \code{rssview.txt} +\end{itemize} + +Le fichier \code{README.txt} d�crit en quelques phrases l'objectif du paquet, +et pr�sente sa structure. + +\codetitle{Fichier README.txt} +\begin{verbatim} +rssreader +========= + +Ce paquet permet de pr�senter des flux rss. Il est organis� en trois +composants: + +- rssreader: sait lire un flux RSS 1.0 +- rssobject: stocke le flux et fourni des m�thodes d'acc�s +- rssview: sait afficher un flux dans le naviguateur +\end{verbatim} + +\noindent Chaque module est pr�sent� � son tour dans un doctest. + +\codetitle{Fichier rssreader.txt} +\begin{verbatim} +rssfetcher +========== + +Le module rssreader transforme un fichier xml au format RSS 1.0 +vers une structure Python exploitable. Il est invoqu� avec l'URL +d'un flux et renvoi une liste contenant les entr�es du flux. +\end{verbatim} + +A ce stade, le d�veloppeur n'a pas encore �crit de code, mais +dispose d'une sp�cification technique et architecturelle exploitable. + +\subsection*{Ins�rer des exemples de codes} + +Sur la base de ces fichiers textes, le d�veloppeur peut commencer +� pr�parer le d�veloppement des modules, en explicitant la face +visible de ces derniers, c'est � dire les API qui seront utilis�es +dans d'autres modules. + +\codetitle{Modification du fichier rssreader.txt} +\begin{verbatim} +rssfetcher +========== + +Le module rssfetcher transforme un fichier xml au format RSS 1.0 +vers une structure Python exploitable. Il est invoqu� avec l'URL +d'un flux et renvoi une liste contenant les entr�es du flux. + +Il fourni une fonction `fetchFeed(source)` qui renvoie une structure Python +en fonction d'une url ou d'un fichier :: + + >>> from rssfetcher import fetchFeed + >>> fetchFeed('tests/rss.xml') + [{'Subject': 'entry one', 'content': "le contenu est ici"}] +\end{verbatim} +\begin{codenotes} +\item Le paquet doit pr�voir dans un sous r�pertoire un fichier +�chantillon \code{rss.xml}, contenant un flux utilis� pour les tests. +\end{codenotes} + +\noindent Ce principe est appliqu� pour l'ensemble des modules du paquet, +susceptibles de fournir des fonctionnalit�s. + +\subsection*{D�velopper les fonctionnalit�s} + +Le doctest pr�c�dent ne peut bien s�r fonctionner que si l'impl�mentation +est r�alis�e. Le d�veloppeur con�oit donc le module \code{rssfetcher.py} +jusqu'� ce que le test du doctest passe. Ce d�veloppement n�cessitera +certainement la cr�ation d'autres tests unitaires, qui seront +con�us classiquement dans des classes dans le sous-r�pertoire de \code{tests}. + +Lorsque tous les modules sont con�us, \code{README.txt} contient un exemple +complet d'utilisation, qui simule g�n�ralement quelques directives ZCML +et quelques �changes avec le publisher. + +\section*{Maintenir et faire �voluer le code} + +L'�volution du paquet, que ce soit dans le cadre d'une correction, ou +d'une modification, doit se faire de la m�me mani�re: les fichiers textes +sont revus en premiers, puis le code est modifi� en cons�quence. + +Les corrections de bugs sont trait�s d'une mani�re particuli�re: +un test unitaire qui reproduit le probl�me est ajout� dans les classes de +tests, et le code invoqu� corrig�. Ajouter ces tests dans les doctests +d�nature leur objectif secondaire: servir de documentation. + +Cependant, si il est explicitement demand� que les bugfix soient document�s, +et facilement lisibles, un doctest \code{bugfix.txt} peut �tre ajout�. +Ce n'est pas le cas pour Zope 3 par exemple, car le couple trac+svn fourni +une bonne tracabilit� des bugfix. +\end{solution} + +\end{document} Added: cookbook/trunk/recipe51.fr.tex ============================================================================== --- (empty file) +++ cookbook/trunk/recipe51.fr.tex Fri Mar 10 18:05:25 2006 @@ -0,0 +1,29 @@ +\documentclass{book} +\pagestyle{headings} +\include{macros} +\status{draft} +\author{Tarek Ziad�} + +\begin{document} + +\chapter*{Enregistrer une session utilisateur pour les tests} + +\begin{problem} +L'�criture d'un test fonctionnel est en souvent dict� par un sc�nario +d'utilisation pr�cis, ou "user story", o� chaque �tape est r�alis�e via +l'interface homme-machine fournie. Dans notre cas, l'interface est bien +s�r le naviguateur. + +Programmer une session web compl�te par code est fastidieux. + +Cette recette pr�sente des techniques pour enregistrer des actions r�alis�es +dans un vrai naviguateur, et les r�cup�rer pour les tests fonctionnels. +\end{problem} + +\begin{solution} +TODO +\end{solution} + +\end{document} + + Modified: cookbook/trunk/recipe7.fr.tex ============================================================================== --- cookbook/trunk/recipe7.fr.tex (original) +++ cookbook/trunk/recipe7.fr.tex Fri Mar 10 18:05:25 2006 @@ -11,35 +11,217 @@ \begin{problem} Les tests fonctionnels, ou "acceptance tests", sont compl�mentaires aux tests unitaires: ce sont des bo�tes noires qui testent les fonctionnalit�s -du syst�me complet, conform�ment � chaque besoin �nonc� par le commanditaire. +du syst�me complet, conform�ment � chaque besoin �nonc�. Ces tests ne se concentrent que sur l'utilisation du syst�me, comme le ferait un utilisateur lambda, pour s'assurer que les fonctionnalit�s attendues sont pr�sentes et fonctionnent. -Ils deviennent �galement un t�moin de qualit� in�galable pour le commanditaire, -qui peut parfois �crire ou �tendre lui-m�me ces tests. +Ils deviennent �galement un t�moin de qualit� in�galable pour l'utilisateur +final, qui peut parfois �crire ou �tendre lui-m�me ces tests. + +En terme de proportion, il est admis qu'un syst�me devrait avoir +approximativement 2/3 de tests unitaires et 1/3 de tests fonctionnels, ces +derniers �tant de plus haut niveau. Pour les applications web, ces tests n�cessitent un environnement d'ex�cution -particulier, qui imite au mieux un naviguateur. C'est l'objectif du paquet -`zope.testbrowser`, qui fourni des outils pour �crire des tests fonctionnels -bas�s sur des �changes avec un naviguateur simul�. +particulier, qui imite au mieux un naviguateur, et fourni des APIs pour +effectuer des requ�tes et �tudier les r�ponses, comme le ferait Firefox +ou Internet Explorer. \end{problem} \begin{solution} -\section*{Principes et fonctionnement de testbrowser} - -todo - -\section*{Simuler une session utilisateur} - -todo - -\section*{Limitations de testbrowser} - -todo - +\section*{Comprendre le fonctionnement} +Un test fonctionnel par d�finition, ne se concentre que sur les fonctionnalit�s +d'une application, sans se soucier des d�tails d'impl�mentation, contrairement +aux tests unitaires. C'est le test pratiqu� par l'utilisateur final, qui peut +par exemple parcourir les menus de l'application, pour tester chacun d'entre +eux. Il valide alors, muni d'une checklist, que chaque fonctionnalit� attendue +est bien pr�sente et se comporte comme souhait�. Le syst�me est alors "valid�" +si la checklist n'a aucun point manquant ou non conforme. + +Les tests fonctionnels en Python et a fortiori avec Zope, se font par le +biais de classes de tests d�riv�es des classe de tests unitaires, ou +dans des doctests. + +Entre tests unitaire et fonctionnel, seule l'interface entre le syst�me et le +testeur change: ce dernier doit se mettre dans les m�mes conditions que +l'utilisateur. + +\subsection*{Faire des tests fonctionnels avec des classes} + +Zope fourni un module sp�cifique dans le paquet \code{zope.app.testing} appel� +\code{functional}, qui fournit des classes d�riv�es de +\code{unittest.TestCase}. La classe la plus utilis�e est +\code{BrowserTestCase}. + +\noindent Elle fournit principalement les m�thodes suivantes: +\begin{itemize} +\item \code{getRootFolder()}: renvoie le dossier racine de Zope. Utilis� +pour manipuler le site avant d'analyser une publication. +\item \code{publish(path, basic=None)}: renvoie le rendu d'un objet pour le +chemin \code{path} sous la forme d'un objet \code{Response}. Si \code{basic} +est fourni, c'est une cha�ne contenant le login et le mot de passe, sous la +forme \code{'login:password'}. La cha�ne 'mgr:mgrpw' peut �tre employ�e +pour s'authentifier avec les droits manager. +\item \code{checkForBrokenLinks(body, path, basic=None)}: v�rifie que +\code{body}, qui est une cha�ne de caract�re repr�sentant le corps d'une +r�ponse (r�cup�r� par \code{Response.getBody()}), ne contient pas de +liens cass�s. \code{path} fourni le chemin relatif qui correspond � l'objet � +l'origine de la r�ponse. Ce param�tre permet � la m�thode de se rep�rer sur +le site pour les r�f�rences relatives. +\end{itemize} + +L'object \code{Response} est un objet renvoy� par le publisher et augment� +par les outils de tests de quelques m�thodes facilitant la lecture. On +retiendra surtout: +\begin{itemize} +\item \code{getBody()}: renvoie le corps de la r�ponse +\item \code{getOutput()}: renvoie la r�ponse compl�te (corps et en-t�tes) +\item \code{getStatus()}: renvoie le status +\item \code{getHeaders()}: permet de r�cuperer les headers +\end{itemize} + +Dans l'exemple ci-dessous, un dossier est cr�� dans le dossier racine, +et son rendu v�rifi�. + +\codetitle{Classe de v�rification du rendu d'un dossier:} +\begin{Verbatim} +>>> import transaction +>>> from zope.app.testing import functional +>>> from buddydemo.buddy import BuddyFolder +>>> class FolderTest(functional.BrowserTestCase): +... def test_folder(self): +... root = self.getRootFolder() +... +... # create a Folder +... root['cool_folder'] = BuddyFolder() +... transaction.commit() +... +... # get the root content through the publisher +... response = self.publish('/cool_folder', basic='mgr:mgrpw') +... self.assert_('<title>Z3: cool_folder</title>' in +... response.getBody()) +\end{Verbatim} +\begin{codenotes} +\item Le code \code{transaction.commit()} permet de valider la modification +effectu�e sur le site, pour la rendre disponible lors de l'appel � +\code{publish}. +\end{codenotes} + +Ce test est ex�cut� comme un test unitaire classique. + +\codetitle{Lancement du test:} +\begin{Verbatim} +>>> import unittest +>>> suite = unittest.makeSuite(FolderTest) +>>> test_runner = unittest.TextTestRunner() +>>> test_runner.run(suite) +<unittest._TextTestResult run=1 errors=0 failures=0> +\end{Verbatim} + +\subsection*{Faire des tests fonctionnels par doctests} + +Les tests fonctionnels sont des tests de tr�s haut niveau, et se rapprochent +beaucoup des exemples de code qu'une documentation peut contenir. Il est +possible en Python d'associer ce besoin documentaire avec les tests par +le biais des doctests. + +\subsubsection*{Comprendre les doctests de Python} + +L'originalit� de Python est de fournir un syst�me de tests bas� sur les +docstrings: le code a tester est �crit dans des docstrings, sous la +forme de s�quences de prompt Python. + +\codetitle{Exemple de doctest:} +\begin{Verbatim} +>>> def laVerite(): +... """ +... >>> laVerite() +... 'les doctests, ca claque' +... """ +... return 'les doctests, ca claque' +\end{Verbatim} + +Le module \code{doctest} de Python fourni des outils pour extraire et ex�cuter +ces tests. + +\codetitle{Execution du doctest:} +\begin{Verbatim} +>>> import doctest +>>> doctest.run_docstring_examples(laVerite, globals(), verbose=True) +Finding tests in NoName +Trying: + laVerite() +Expecting: + 'les doctests, ca claque' +ok +\end{Verbatim} + +Cependant, les tests contenus dans les doctests de chaque module, +classe et fonction parasitent la lisibilit� du code. Pour �viter cette +obfuscation, il est possible de les regrouper dans un fichier texte s�par� du +code, et "ex�cuter" ce fichier. Les exemples peuvent alors �tre agr�ment�s +d'explications et suivre un d�roulement logique. On parle alors de +"documentation agile", ou "documentation ex�cutable". + +Ces documents peuvent ensuite �tre appel�s comme module de test. + +\codetitle{Document agile:} +\begin{verbatim} +Le module verite +================ + +Ce document ne contient pas de tests fonctionnels mais plut�t un test unitaire. + +Ce n'est pas bien grave. + +Le module v�rit� contient une fonction `laVerite()` qui peut �tre appel�e +pour afficher un message. Cette m�thode ne sert pas � grand chose. + +Exemple d'utilisation:: + + >>> from verite import laVerite + >>> laVerite() + 'les doctests, ca claque' +\end{verbatim} + +\subsubsection*{Comprendre les doctests fonctionnels dans Zope} + +Pour manipuler facilement Zope dans les doctests, le paquet +\code{zope.testbrowser} fourni une classe \code{Browser} qui permet +de simuler un naviguateur et ses fonctionalit�s. Par convention, cette classe +est invoqu�e avec une URL qui commence par \url{http://localhost}, puis le +chemin sur le serveur Zope. + +Atteindre la page � la racine peut donc s'�crire ainsi: +\begin{Verbatim} +>>> from zope.testbrowser.testing import Browser +>>> browser = Browser('http://localhost') +>>> browser.url +'http://localhost' +>>> browser.contents +'...<title>Z3: </title>...' +\end{Verbatim} +\begin{codenotes} +\item La propri�t� \code{contents} permet de r�cup�rer le contenu de la page sous +forme d'une cha�ne de caract�res. +\item Les '...' (ou Ellipsis) ont une signification pr�cise dans les doctests: +ils servent � remplacer une portion de texte quelconque. Dans l'exemple ci +dessus, ils permettent de s'assure que \code{contents} contient bien la portion +HTML indiqu�e. +\end{codenotes} + +AFINIR ici + +\section*{Limitations des tests fonctionnels} + +Les tests fonctionnels web ont une limitation inh�rente au fonctionnement des +naviguateurs: il est impossible de tester le javascript contenu dans les pages +car chaque naviguateur impl�mente son propre moteur. Il faut utiliser d'autres +techniques, bas�es par exemple sur le syst�me de test \textit{Selenium}, qui +lance les tests depuis un naviguateur r�el. \end{solution} \end{document} Modified: cookbook/trunk/recipe_list.txt ============================================================================== --- cookbook/trunk/recipe_list.txt (original) +++ cookbook/trunk/recipe_list.txt Fri Mar 10 18:05:25 2006 @@ -32,7 +32,7 @@ 04 - the zope component architecture 05 - understanding the development process 06 - writing unit tests -07 - writing functional tests +07 - writing functional tests (TZ) 08 - debugging the code 09 - understanding Interfaces 10 - understanding the traversal @@ -61,6 +61,15 @@ 45 - creating an internationalized package 46 - creating multilanguage content objects 47 - changing and migrating existing objects +48 - writing reSTructuredText for documentation and doctests (TZ) +49 - using zapi in tests (TZ) +50 - organizing tests in a package (TZ) +51 - finding the good pace between coding, documenting, unit testing and + functionnal testing (TZ) +52 - recording a user web session to write tests (TZ) +53 - organizing the code in a package (TZ) +54 - using ldap to store users +55 - using a sql database to store data - ... Developping Zope - advanced recipes Modified: cookbook/trunk/tests.py ============================================================================== --- cookbook/trunk/tests.py (original) +++ cookbook/trunk/tests.py Fri Mar 10 18:05:25 2006 @@ -1,38 +1,83 @@ +# -*- coding: ISO-8859-15 -*- +# Copyright (c) 2004 Tarek Ziad� and contributors +# Author: Tarek Ziad� <[EMAIL PROTECTED]> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 as published +# by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +# 02111-1307, USA. +""" run all latex recipes files contained in the + current directory as functionnal doctests, + using zope environnement +""" import doctest import os import unittest -import re +from zope.app.testing import setup, functional +from textest import TexFileSuite +def FunctionalTexFileSuite(filename, **kw): + globs = kw.setdefault('globs', {}) + globs['http'] = functional.HTTPCaller() + globs['getRootFolder'] = functional.getRootFolder + globs['sync'] = functional.sync + kw['package'] = doctest._normalize_module(kw.get('package')) + + kwsetUp = kw.get('setUp') + def setUp(test): + functional.FunctionalTestSetup().setUp() + setup.setUpTestAsModule(test, filename.replace('.', '_')) + if kwsetUp is not None: + kwsetUp(test) + + kw['setUp'] = setUp + + kwtearDown = kw.get('tearDown') + def tearDown(test): + if kwtearDown is not None: + kwtearDown(test) + try: + setup.tearDownTestAsModule(test) + except KeyError: + # XXX see why + pass + functional.FunctionalTestSetup().tearDown() + + kw['tearDown'] = tearDown + + if 'optionflags' not in kw: + old = doctest.set_unittest_reportflags(0) + doctest.set_unittest_reportflags(old) + kw['optionflags'] = (old + | doctest.ELLIPSIS + | doctest.REPORT_NDIFF + | doctest.NORMALIZE_WHITESPACE) + + suite = TexFileSuite(filename, **kw) + suite.layer = functional.Functional + return suite -extracter = r'\\begin{Verbatim}(?P<contents>.*?)\\end{Verbatim}' -cExtracter = re.compile(extracter, re.MULTILINE| re.DOTALL) current_folder = os.path.dirname(__file__) if current_folder == '': current_folder = '.' - def test_suite(): - options = doctest.ELLIPSIS extractor = doctest.DocTestParser() - tests = [] - - for file in os.listdir(current_folder): - if not file.endswith('.tex'): - continue - - content = open('%s/%s' % (current_folder, file)).read() - match_obj = cExtracter.search(content) - if match_obj is None: - continue - - content = match_obj.group('contents').strip() - - file_tests = extractor.get_doctest(content, globals(), file, file, - None) - tests.append(doctest.DocFileCase(file_tests)) + files = [file for file in os.listdir(current_folder) + if file.endswith('.tex')] + tests = [FunctionalTexFileSuite(file) for file in files] return unittest.TestSuite(tests) if __name__ == '__main__': Added: cookbook/trunk/tests.txt ============================================================================== --- (empty file) +++ cookbook/trunk/tests.txt Fri Mar 10 18:05:25 2006 @@ -0,0 +1,41 @@ +Latex test environment +______________________ + +The textest and tests modules are used by Zope 3 test script. + +Each latex file in this folder is ran like a doctest, with a filtering of the +text content, wich is based on the extraction of `Verbatim` sections. + +`verbatim` sections are not run on purpose, so your latex files +can contain examples you don't want to run in tests. + +If you create classes in your latex file, and you need to reach them for +example in a zcml class directive, the module name is the file name, +with dots replaced by underlines. + +For example, in recipeX.fr.tex:: + + >>> class FolderListing: + ... def contents(self): + ... return list(self.context.keys()) + >>> from zope.configuration import xmlconfig + >>> ignored = xmlconfig.string(""" + ... <configure + ... xmlns="http://namespaces.zope.org/zope" + ... xmlns:xmlrpc="http://namespaces.zope.org/xmlrpc" + ... > + ... <include package="zope.app.publisher.xmlrpc" file="meta.zcml" /> + ... + ... <xmlrpc:view + ... for="zope.app.folder.folder.IFolder" + ... methods="contents" + ... class="recipeX_fr_tex.FolderListing" + ... permission="zope.ManageContent" + ... /> + ... </configure> + ... """) + + + + + Added: cookbook/trunk/textest.py ============================================================================== --- (empty file) +++ cookbook/trunk/textest.py Fri Mar 10 18:05:25 2006 @@ -0,0 +1,71 @@ +# -*- coding: ISO-8859-15 -*- +# Copyright (c) 2004 Tarek Ziad� and contributors +# Author: Tarek Ziad� <[EMAIL PROTECTED]> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 as published +# by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +# 02111-1307, USA. +""" textest is similar to doctest but to be used + with latex files. +""" +import doctest +import os +import unittest +import re +import sys +from StringIO import StringIO +import pdb + +extracter = r'\\begin{Verbatim}(?P<contents>.*?)\\end{Verbatim}' +cExtracter = re.compile(extracter, re.MULTILINE| re.DOTALL) + +def _latexfilter(source): + code_blocs = cExtracter.findall(source) + if code_blocs == []: + return source + return ''.join(code_blocs).strip() + +def TexFileTest(path, module_relative=True, package=None, + globs=None, parser=doctest.DocTestParser(), **options): + if globs is None: + globs = {} + + if package and not module_relative: + raise ValueError("Package may only be specified for module-" + "relative paths.") + + # Relativize the path. + if module_relative: + package = doctest._normalize_module(package) + path = doctest._module_relative_path(package, path) + + # Find the file and read it. + name = os.path.basename(path) + doc = open(path).read() + doc = _latexfilter(doc) + + # Convert it to a test, and wrap it in a DocFileCase. + test = parser.get_doctest(doc, globs, name, path, 0) + return doctest.DocFileCase(test, **options) + + +def TexFileSuite(*paths, **kw): + suite = unittest.TestSuite() + + if kw.get('module_relative', True): + kw['package'] = doctest._normalize_module(kw.get('package')) + + for path in paths: + suite.addTest(TexFileTest(path, **kw)) + + return suite -- http://lists.nuxeo.com/mailman/listinfo/z3lab-checkins