diff options
Diffstat (limited to 'TDD')
-rw-r--r-- | TDD/images/fossee-logo.png | bin | 0 -> 13587 bytes | |||
-rw-r--r-- | TDD/images/iitb-logo.png | bin | 0 -> 13756 bytes | |||
-rw-r--r-- | TDD/math_utils/fibonacci.py | 7 | ||||
-rw-r--r-- | TDD/math_utils/fibonacci_testcases.dat | 8 | ||||
-rw-r--r-- | TDD/math_utils/test_fibonacci.py | 27 | ||||
-rwxr-xr-x | TDD/two_column.py | 84 | ||||
-rw-r--r-- | TDD/using_python_framework_for_tdd/tdd2.tex (renamed from TDD/using_python_frameworks_for_TDD/slide.tex) | 232 | ||||
-rwxr-xr-x | TDD/using_python_framework_for_tdd/tdd2_script.rst | 198 |
8 files changed, 473 insertions, 83 deletions
diff --git a/TDD/images/fossee-logo.png b/TDD/images/fossee-logo.png Binary files differnew file mode 100644 index 0000000..49d1797 --- /dev/null +++ b/TDD/images/fossee-logo.png diff --git a/TDD/images/iitb-logo.png b/TDD/images/iitb-logo.png Binary files differnew file mode 100644 index 0000000..38ec17e --- /dev/null +++ b/TDD/images/iitb-logo.png diff --git a/TDD/math_utils/fibonacci.py b/TDD/math_utils/fibonacci.py new file mode 100644 index 0000000..0f454d6 --- /dev/null +++ b/TDD/math_utils/fibonacci.py @@ -0,0 +1,7 @@ +def fibonacci(n): + if n == 0: + return 0 + elif n == 1: + return 1 + else: + return fibonacci(n-1) + fibonacci(n-2) diff --git a/TDD/math_utils/fibonacci_testcases.dat b/TDD/math_utils/fibonacci_testcases.dat new file mode 100644 index 0000000..c5dae1a --- /dev/null +++ b/TDD/math_utils/fibonacci_testcases.dat @@ -0,0 +1,8 @@ +0, 0 +1, 1 +2, 1 +3, 2 +4, 3 +5, 5 +6, 8 +7, 13 diff --git a/TDD/math_utils/test_fibonacci.py b/TDD/math_utils/test_fibonacci.py new file mode 100644 index 0000000..ee3393f --- /dev/null +++ b/TDD/math_utils/test_fibonacci.py @@ -0,0 +1,27 @@ +import fibonacci +import unittest + +class TestFibonacciFunction(unittest.TestCase): + + def setUp(self): + self.test_file = open('fibonacci_testcases.dat') + self.test_cases = [] + for line in self.test_file: + values = line.split(', ') + n = int(values[0]) + a = int(values[1]) + + self.test_cases.append([n, a]) + + def test_fibonacci(self): + for case in self.test_cases: + n = case[0] + a = case[1] + self.assertEqual(fibonacci.fibonacci(n),a) + + def tearDown(self): + self.test_file.close() + del self.test_cases + +if __name__ == '__main__': + unittest.main() diff --git a/TDD/two_column.py b/TDD/two_column.py new file mode 100755 index 0000000..4134b2e --- /dev/null +++ b/TDD/two_column.py @@ -0,0 +1,84 @@ +#!/usr/bin/env python +# This script generates two column format from the script file. +import re, optparse + +num = 0 +content = {} + +def parse_script(script): + """Parse the file, and get each cell's content into a dictionary.""" + where = 'HEAD' + txt = '' + global num + for line in open(script): + if line.startswith('..'): + loc = re.findall(".. ((L|R)(\d+))", line) + if loc: + # Next cell has been found + # Save previous cell data + content[where] = txt + + txt = '' + where = loc[0][0] + num = int(loc[0][2]) if int(loc[0][2]) > num else num + continue + else: + pass + txt += line + content[where] = txt # Saving the content of the last cell. + +def write_two_col(content, two_col): + """ Write the content to a file, in two column format.""" + f = open(two_col, 'w') + f.write('%s' %content['HEAD']) + + f.write("\n\n+%s+%s+\n" %('-'*82, '-'*82)) + for i in range(1, num+1): + l = '%s%s' %('L', i) + r = '%s%s' %('R', i) + + # Split each side text into individual lines + if l in content: + ltext = content[l].strip().splitlines() + else: + ltext = [''] + if r in content: + rtext = content[r].strip().splitlines() + else: + rtext = [''] + + # Ensure that both sides have the same number of lines + ltext.extend(['']*(len(rtext) - len(ltext))) + rtext.extend(['']*(len(ltext) - len(rtext))) + + # Write each of the lines in respective columns + for k in range(len(ltext)): + f.write("| %-80s | %-80s |\n" %(ltext[k], rtext[k])) + + # Horizontal division + f.write("+%s+%s+\n" %('-'*82, '-'*82)) + + f.close() + +if __name__ == '__main__': + parser = optparse.OptionParser() + parser.add_option("-i", default="script.rst", dest="input", + help="Input file. 'script.rst' is used by default.") + parser.add_option("-o", default="script2col.rst", dest="output", + help="Output file. script2col.rst is used by default.") + + parser.description = """Converts a script file into two column format.""" + + parser.epilog = \ + """Make sure that you check the validity of the formatting of both +the INPUT and the OUTPUT files, using rst2html. Also, Make sure that +each line, in the INPUT file, is less than 80 chars long.""" + + (options, args) = parser.parse_args() + + script, two_col = options.input, options.output + + parse_script(script) + write_two_col(content, two_col) + + print "Converted %s to 2 column format and saved as %s" %(script, two_col) diff --git a/TDD/using_python_frameworks_for_TDD/slide.tex b/TDD/using_python_framework_for_tdd/tdd2.tex index a6308c4..561f4a2 100644 --- a/TDD/using_python_frameworks_for_TDD/slide.tex +++ b/TDD/using_python_framework_for_tdd/tdd2.tex @@ -22,61 +22,98 @@ commentstyle=\color{red}\itshape, stringstyle=\color{green}, showstringspaces=false, keywordstyle=\color{blue}\bfseries} \providecommand{\alert}[1]{\textbf{#1}} -\title{Getting started with TDD} +\title{SEES: Test Driven Development} \author{FOSSEE} -\institute{IIT Bombay} \usetheme{Warsaw}\usecolortheme{default}\useoutertheme{infolines}\setbeamercovered{transparent} -\AtBeginSection[] -{ - \begin{frame}<beamer> - \frametitle{Outline} - \tableofcontents[currentsection] - \end{frame} -} +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + \begin{document} -\begin{frame} +\begin{frame} \begin{center} \vspace{12pt} -\textcolor{blue}{\huge Using Python Testing Frameworks} +\textcolor{blue}{\huge Test Driven Development \\Part II} \end{center} \vspace{18pt} \begin{center} \vspace{10pt} -\includegraphics[scale=0.95]{../../images/fossee-logo.png}\\ +\includegraphics[scale=0.95]{../images/fossee-logo.png}\\ \vspace{5pt} \scriptsize Developed by FOSSEE Team, IIT-Bombay. \\ \scriptsize Funded by National Mission on Education through ICT\\ \scriptsize MHRD,Govt. of India\\ -\includegraphics[scale=0.30]{../../images/iitb-logo.png}\\ +\includegraphics[scale=0.30]{../images/iitb-logo.png}\\ \end{center} \end{frame} - +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\section{Introduction} \begin{frame} \frametitle{Objectives} - At the end of this section, you will be able to: + At the end of this tutorial, you will be able to, \begin{itemize} - \item Use doctests to test your Python code. - \item Use unittests to test your Python code. - \item Use the nose module to test your code. + \item Know what are persistent test cases. + \item Write doctest \& unittest for any given function. + \item Understand the use of nosetest. + \end{itemize} -\end{frame} + \end{frame} +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \begin{frame} \frametitle{Pre-requisite} \label{sec-3} -Spoken tutorial on Basic Python +Spoken tutorial on - \begin{itemize} -\item Topic of tutorial here +\item Test Driven Development -- Part I \end{itemize} \end{frame} +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - +\begin{frame}[fragile] + \frametitle{Persistent Test Cases} + \begin{itemize} + \item Tests should be pre-determined and written, before the code + \item Test Data is repeatedly used; Hence, saved in persistent + format + \item Let's save data for fibonacci tests in a text file. + \item The file shall have multiple lines of test data + \item Each line corresponds to a single test case + \item Each line consists of two comma separated values -- + \begin{itemize} + \item First coloumn is the integer which has to be + passed to the function. + \item Second coloumn is the return value from the function. + \end{itemize} + \item Let us call our data file \texttt{fibonacci\_testcases.dat} + \end{itemize} +\end{frame} +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\begin{frame}[fragile] + \frametitle{Modify \texttt{fibonacci.py}} +\begin{lstlisting} +if __name__ == '__main__': + for line in open('fibonacci_testcases.dat'): + values = line.split(', ') + n = int(values[0]) + a = int(values[1]) + + tc = fibonacci(n) + if tc != a: + print "Failed for n=%d.\ + Expected %d. Obtained %d instead."\ + % (n, a, tc) + exit(1) + + print "All tests passed!" +\end{lstlisting} +\end{frame} +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \section{Python Testing Frameworks} \begin{frame}[fragile] @@ -90,7 +127,7 @@ Spoken tutorial on Basic Python \end{itemize} \end{itemize} \end{frame} - +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \subsection{\texttt{doctest} module} \begin{frame}[fragile] @@ -104,32 +141,33 @@ Spoken tutorial on Basic Python \item \texttt{doctest} module picks up all such interactive examples \item Executes them and determines if the code runs, as documented \end{itemize} - Let's use the \texttt{doctest} module for our \texttt{gcd} function + Let's use the \texttt{doctest} module for our \texttt{fibonacci} function \end{frame} +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \begin{frame}[fragile] - \frametitle{doctest for \texttt{gcd.py}} + \frametitle{doctest for \texttt{fibonacci.py}} \begin{tiny} \begin{lstlisting} -def gcd(a, b): - """Returns the Greatest Common Divisor of the two integers - passed as arguments. +def fibonacci(n): + """Returns the nth fibonacci number. Args: - a: an integer - b: another integer - - Returns: Greatest Common Divisor of a and b - - >>> gcd(48, 64) - 16 - >>> gcd(44, 19) - 1 + n: an integer + + + >>> fibonacci(3) + 2 + >>> fibonacci(4) + 3 """ - if b == 0: - return a - return gcd(b, a%b) + if n == 0: + return 0 + elif n == 1: + return 1 + else: + return fibonacci(n-1) + fibonacci(n-2) \end{lstlisting} \end{tiny} \begin{itemize} @@ -137,9 +175,9 @@ def gcd(a, b): \item Now we need to tell the \texttt{doctest} module to execute \end{itemize} \end{frame} - +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \begin{frame}[fragile] - \frametitle{doctest for \texttt{gcd.py} \ldots} + \frametitle{doctest for \texttt{fibonacci.py} \ldots} \begin{lstlisting} if __name__ == "__main__": import doctest @@ -152,18 +190,18 @@ if __name__ == "__main__": \item Complains only when one or more tests fail. \end{itemize} \end{frame} - +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \begin{frame}[fragile] \frametitle{\texttt{doctest} -- Execution} \begin{itemize} - \item Run the doctests by running \texttt{gcd.py} + \item Run the doctests by running \texttt{fibonacci.py} \begin{lstlisting} -$ python gcd.py +$ python fibonacci.py \end{lstlisting} %$ \item All the tests pass, and doctest gives no output \item For a more detailed report we can run with -v argument \begin{lstlisting} -$ python gcd.py -v +$ python fibonacci.py -v \end{lstlisting} %$ \item If the output contains a blank line, use \texttt{<BLANKLINE>} \item To see a failing test case, replace \texttt{return a} with \texttt{b} @@ -171,7 +209,7 @@ $ python gcd.py -v \end{frame} \subsection{\texttt{unittest} framework} - +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \begin{frame}[fragile] \frametitle{\texttt{unittest}} \begin{itemize} @@ -184,57 +222,43 @@ $ python gcd.py -v \item Easily aggregate tests into collections and improved reporting \end{itemize} \end{frame} - +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \begin{frame}[fragile] - \frametitle{\texttt{unittest}} - \begin{itemize} - \item It won't be long, before we complain about the power of - \texttt{doctest} - \item \texttt{unittest} framework can efficiently automate tests - \item Easily initialize code and data for executing the specific - tests - \item Cleanly shut them down once the tests are executed - \item Easily aggregate tests into collections and improved reporting - \end{itemize} -\end{frame} - -\begin{frame}[fragile] - \frametitle{\texttt{unittest}ing \texttt{gcd.py}} + \frametitle{\texttt{unittest}ing \texttt{fibonacci.py}} \begin{itemize} \item Subclass the \texttt{TestCase} class in \texttt{unittest} \item Place all the test code as methods of this class - \item Use the test cases present in \texttt{gcd\_testcases.dat} - \item Place the code in \texttt{test\_gcd.py} + \item Use the test cases present in \texttt{fibonacci\_testcases.dat} + \item Place the code in \texttt{test\_fibonacci.py} \end{itemize} \end{frame} - +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \begin{frame}[fragile,allowframebreaks] - \frametitle{\texttt{test\_gcd.py}} + \frametitle{\texttt{test\_fibonacci.py}} \small \begin{lstlisting} -import gcd +import fibonacci import unittest -class TestGcdFunction(unittest.TestCase): +class TestFibonacciFunction(unittest.TestCase): def setUp(self): - self.test_file = open('gcd_testcases.dat') + self.test_file = \ + open('fibonacci_testcases.dat') self.test_cases = [] for line in self.test_file: values = line.split(', ') - a = int(values[0]) - b = int(values[1]) - g = int(values[2]) - - self.test_cases.append([a, b, g]) + n = int(values[0]) + a = int(values[1]) + + self.test_cases.append([n, a]) - def test_gcd(self): + def test_fibonacci(self): for case in self.test_cases: - a = case[0] - b = case[1] - g = case[2] - self.assertEqual(gcd.gcd(a, b), g) + n = case[0] + a = case[1] + self.assertEqual(fibonacci.fibonacci(n),a) def tearDown(self): self.test_file.close() @@ -244,22 +268,22 @@ if __name__ == '__main__': unittest.main() \end{lstlisting} \end{frame} - +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \begin{frame}[fragile] - \frametitle{\texttt{test\_gcd.py}} + \frametitle{\texttt{test\_fibonacci.py}} \begin{itemize} \item \texttt{setUp} -- we read all the test data and store it in a list \item \texttt{tearDown} -- delete the data to free up memory and close open file - \item \texttt{test\_gcd} -- actual test code + \item \texttt{test\_fibonacci} -- actual test code \item \texttt{assertEqual} -- compare actual result with expected one \item Write documentation for above code. \end{itemize} \end{frame} \section{\texttt{nose}} - +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \begin{frame}[fragile] \frametitle{\texttt{nose} tests} \begin{itemize} @@ -281,6 +305,47 @@ $ nosetests \end{itemize} \end{frame} +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\begin{frame} +\frametitle{Summary} +\label{sec-8} + + In this tutorial, we have learnt to, + + +\begin{itemize} +\item Use of persistent test cases for better control. +\item Undestand the use of doctest \& unittest. +\item Understand the use of nosetest . + +\end{itemize} +\end{frame} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\begin{frame}[fragile] +\frametitle{Evaluation} +\label{sec-9} + + +\begin{enumerate} +\item ? +\vspace{8pt} +\item ? +\end{enumerate} +\end{frame} +\begin{frame} +\frametitle{Solutions} +\label{sec-10} + + +\begin{enumerate} +\item +\vspace{15pt} +\item +\end{enumerate} +\end{frame} +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + \begin{frame} \begin{block}{} @@ -296,4 +361,5 @@ $ nosetests \end{block} \end{frame} + \end{document} diff --git a/TDD/using_python_framework_for_tdd/tdd2_script.rst b/TDD/using_python_framework_for_tdd/tdd2_script.rst new file mode 100755 index 0000000..85c96d5 --- /dev/null +++ b/TDD/using_python_framework_for_tdd/tdd2_script.rst @@ -0,0 +1,198 @@ +.. Objectives +.. ---------- + + .. At the end of this tutorial, you will be able to: + + .. 1. Know what is TDD. + .. 2. Understand the use of test cases. + .. 3. Write simple tests for a function. + +.. Prerequisites +.. ------------- + +.. 1. Test driven development - Part 1 + + +Script +------ + +.. L1 + +{{{ Show the first slide containing title, name of the production +team along with the logo of MHRD }}} + +.. R1 + +Hello friends and Welcome to the tutorial on +'Test driven development - Part 2'. + +.. L2 + +{{{ Show slide with objectives }}} + +.. R2 + +At the end of this tutorial, you will be able to, + + 1. understand use of persistent test cases. + #. write doctest and unittest for any given function. + #. and understand the use of nosetest. + +.. L3 + +{{{ Switch to the slide3, pre-requisite slide }}} + +.. R3 + +Before beginning this tutorial,we would suggest you to complete the +tutorial on "Test driven development-part 1". + +.. R4 + + + +.. L4 + +{{{ Switch to slide4 ,Persistent test cases}}} + + +.. R5 + +To illustrate TDD, lets take a simple program. Consider a +function ``fibonacci``, that takes one argument and returns +the nth number of ``fibonacci`` series. + +.. L5 + +{{{ Switch to slide5, First test- fibonacci }}} + +.. R6 + +To test ``fibonacci`` function, we need test +cases. +As shown in this slide, +test cases are expected outputs for a given set of inputs. + + +.. L6 + +{{{ Switch to slide6, Test cases }}} + +.. R7 + +The sample code for test cases is shown here. Observe that if +any ``if`` statement is executed, test aborts after printing the +error message. + +.. L7 + +{{{ Switch to slide7, Test cases-Code }}} + +.. R8 + +The ``fibonacci`` function is written just enough so that +test can run. + + +.. L8 + +{{{ switch to slide8, Stubs }}} + +.. R9 + +Combine the function and test cases and put them together in +``fibonacci.py`` file.Add the test cases after name=main idiom. + +.. L9 + +{{{ Switch to slide9, fibonacci.py }}} + +.. R10 + +Lets run fibonacci.py by typing ``python fibonacci.py``. +As we haven't written any meaningful code in our ``fibonacci`` +function, it fails immediately. +Our next step is to write just minimum code to pass our tests. + +.. L10 + +{{{ Run the fibonacci.py in terminal and show the error output.}}} +:: + + python fibonacci.py + +.. R11 + +Modify the fibonacci stub function with given code. +Save and run it again as `` python fibonacci.py``. +{{{ pause }}} +Observe that, there will be no errors, as +the test passes successfully. + +.. L11 + +{{{ switch to slide-11, Euclidean Algorithm }}} +Switch to terminal and modify fibonacci function in ``nano`` +editor and run. +:: + + python fibonacci.py + +.. R12 + +The same ``fibonacci`` function is modified to make it more readable +and easy to understand using recursion. +Pause this video here.Replace the ``fibonacci`` function with recursive one. +Run the modified ``fibonacci.py`` file. The test should pass again +without any errors. +After successfully achieving this result, you can resume the video. + +.. L12 + +{{{ Show slide12, Euclidean Algorithm- Recursive}}} + + +.. R13 + +This brings us to the end of the tutorial.In this tutorial, + we have learnt to, + + 1. Undestand the basic steps involved in Test driven development. + #. Design a Test driven approach for a given ``fibonacci`` function. + + +.. L13 + +{{{ switch to slide-13,Summary }}} + +.. R14 + +Here are some self assessment questions for you to solve + 1. + + 2. + +.. L14 + +{{{ switch to slide-14, Evaluation }}} + +.. R15 + +And the answers are, + 1. + + 2. + +.. L15 + +{{{ switch to slide-15 ,Solutions}}} + +.. R16 + +Hope you have enjoyed this tutorial and found it useful. +Thank you! + +.. L16 + +{{{ Switch to slide-16, Thankyou}}} + |