summaryrefslogtreecommitdiff
path: root/slides/test_driven_development
diff options
context:
space:
mode:
Diffstat (limited to 'slides/test_driven_development')
-rw-r--r--slides/test_driven_development/tdd_simple.tex342
1 files changed, 342 insertions, 0 deletions
diff --git a/slides/test_driven_development/tdd_simple.tex b/slides/test_driven_development/tdd_simple.tex
new file mode 100644
index 0000000..ae57c69
--- /dev/null
+++ b/slides/test_driven_development/tdd_simple.tex
@@ -0,0 +1,342 @@
+\documentclass[12pt,presentation]{beamer}
+\usepackage[utf8]{inputenc}
+\usepackage[T1]{fontenc}
+\usepackage{fixltx2e}
+\usepackage{graphicx}
+\usepackage{longtable}
+\usepackage{float}
+\usepackage{wrapfig}
+\usepackage{soul}
+\usepackage{textcomp}
+\usepackage{marvosym}
+\usepackage{wasysym}
+\usepackage{latexsym}
+\usepackage{amssymb}
+\usepackage{hyperref}
+\tolerance=1000
+\usepackage[english]{babel} \usepackage{ae,aecompl}
+\usepackage{mathpazo,courier,euler} \usepackage[scaled=.95]{helvet}
+\usepackage{listings}
+\lstset{language=Python, basicstyle=\ttfamily\bfseries,
+commentstyle=\color{red}\itshape, stringstyle=\color{green},
+showstringspaces=false, keywordstyle=\color{blue}\bfseries}
+\providecommand{\alert}[1]{\textbf{#1}}
+
+\title{SEES: Test Driven Development}
+\author{FOSSEE}
+
+\usetheme{Warsaw}\usecolortheme{default}\useoutertheme{infolines}\setbeamercovered{transparent}
+
+\AtBeginSection[]
+{
+ \begin{frame}<beamer>
+ \frametitle{Outline}
+ \tableofcontents[currentsection]
+ \end{frame}
+}
+
+\begin{document}
+
+\maketitle
+
+\begin{frame}
+\frametitle{Outline}
+\setcounter{tocdepth}{3}
+\tableofcontents
+\end{frame}
+
+\section{Introduction}
+
+\begin{frame}
+ \frametitle{Objectives}
+ At the end of this section, you will be able to:
+ \begin{itemize}
+ \item Write your code using the TDD paradigm.
+ \item Use the nose module to test your code.
+ \end{itemize}
+\end{frame}
+
+\begin{frame}
+ \frametitle{What is TDD?}
+ The basic steps of TDD are roughly as follows --
+ \begin{enumerate}
+ \item<1-> Decide upon feature to implement and methodology of
+ testing
+ \item<2-> Write tests for feature decided upon
+ \item<3-> Just write enough code, so that the test can be run, but it fails.
+ \item<4-> Improve the code, to just pass the test and at the same time
+ passing all previous tests.
+ \item<5-> Run the tests to see, that all of them run successfully.
+ \item<6-> Refactor the code you've just written -- optimize the algorithm,
+ remove duplication, add documentation, etc.
+ \item<7-> Run the tests again, to see that all the tests still pass.
+ \item<8-> Go back to 1.
+ \end{enumerate}
+\end{frame}
+
+\section{First Test}
+
+\begin{frame}[fragile]
+ \frametitle{First Test -- GCD}
+ \begin{itemize}
+ \item simple program -- GCD of two numbers
+ \item What are our code units?
+ \begin{itemize}
+ \item Only one function \texttt{gcd}
+ \item Takes two numbers as arguments
+ \item Returns one number, which is their GCD
+ \end{itemize}
+\begin{lstlisting}
+c = gcd(44, 23)
+\end{lstlisting}
+ \item c will contain the GCD of the two numbers.
+ \end{itemize}
+\end{frame}
+
+\begin{frame}[fragile]
+ \frametitle{Test Cases}
+ \begin{itemize}
+ \item Important to have test cases and expected outputs even before
+ writing the first test!
+ \item $a=48$, $b=48$, $GCD=48$
+ \item $a=44$, $b=19$, $GCD=1$
+ \item Tests are just a series of assertions
+ \item True or False, depending on expected and actual behavior
+ \end{itemize}
+
+\end{frame}
+
+\begin{frame}[fragile]
+ \frametitle{Test Cases -- general idea}
+\begin{lstlisting}
+tc1 = gcd(48, 64)
+if tc1 != 16:
+ print "Failed for a=48, b=64. Expected 16. \
+ Obtained %d instead." % tc1
+ exit(1)
+
+tc2 = gcd(44, 19)
+if tc2 != 1:
+ print "Failed for a=44, b=19. Expected 1. \
+ Obtained %d instead." % tc2
+ exit(1)
+
+print "All tests passed!"
+\end{lstlisting}
+\begin{itemize}
+\item The function \texttt{gcd} doesn't even exist!
+\end{itemize}
+\end{frame}
+
+
+\begin{frame}[fragile]
+ \frametitle{Test Cases -- code}
+ \begin{itemize}
+ \item Let us make it a function!
+ \item Use assert!
+ \end{itemize}
+\end{frame}
+
+\begin{frame}[fragile]
+ \frametitle{Test Cases -- code}
+\begin{lstlisting}
+# gcd.py
+def test_gcd():
+ assert gcd(48, 64) == 16
+ assert gcd(44, 19) == 1
+
+test_gcd()
+\end{lstlisting}
+\end{frame}
+
+\begin{frame}[fragile]
+ \frametitle{Stubs}
+ \begin{itemize}
+ \item First write a very minimal definition of \texttt{gcd}
+ \begin{lstlisting}
+def gcd(a, b):
+ pass
+ \end{lstlisting}
+ \item Written just, so that the tests can run
+ \item Obviously, the tests are going to fail
+ \end{itemize}
+\end{frame}
+
+\begin{frame}[fragile]
+ \frametitle{\texttt{gcd.py}}
+\begin{lstlisting}
+def gcd(a, b):
+ pass
+
+def test_gcd():
+ assert gcd(48, 64) == 16
+ assert gcd(44, 19) == 1
+
+if __name__ == '__main__':
+ test_gcd()
+\end{lstlisting}
+\end{frame}
+
+\begin{frame}[fragile]
+ \frametitle{First run}
+\begin{lstlisting}
+$ python gcd.py
+Traceback (most recent call last):
+ File "gcd.py", line 9, in <module>
+ test_gcd()
+ File "gcd.py", line 5, in test_gcd
+ assert gcd(48, 64) == 16
+AssertionError
+\end{lstlisting} %$
+
+ \begin{itemize}
+ \item We have our code unit stub, and a failing test.
+ \item The next step is to write code, so that the test just passes.
+ \end{itemize}
+\end{frame}
+
+\begin{frame}[fragile]
+ \frametitle{Euclidean Algorithm}
+ \begin{itemize}
+ \item Modify the \texttt{gcd} stub function
+ \item Then, run the script to see if the tests pass.
+ \end{itemize}
+\begin{lstlisting}
+def gcd(a, b):
+ if a == 0:
+ return b
+ while b != 0:
+ if a > b:
+ a = a - b
+ else:
+ b = b - a
+ return a
+\end{lstlisting}
+\begin{lstlisting}
+$ python gcd.py
+All tests passed!
+\end{lstlisting} %$
+ \begin{itemize}
+ \item \alert{Success!}
+ \end{itemize}
+\end{frame}
+
+
+\begin{frame}[fragile]
+ \frametitle{Euclidean Algorithm -- Modulo}
+ \begin{itemize}
+ \item Repeated subtraction can be replaced by a modulo
+ \item modulo of \texttt{a\%b} is always less than b
+ \item when \texttt{a < b}, \texttt{a\%b} equals \texttt{a}
+ \item Combine these two observations, and modify the code
+\begin{lstlisting}
+def gcd(a, b):
+ while b != 0:
+ a, b = b, a % b
+ return a
+\end{lstlisting}
+ \item Check that the tests pass again
+ \end{itemize}
+\end{frame}
+
+\begin{frame}[fragile]
+ \frametitle{Euclidean Algorithm -- Recursive}
+ \begin{itemize}
+ \item Final improvement -- make \texttt{gcd} recursive
+ \item More readable and easier to understand
+\begin{lstlisting}
+def gcd(a, b):
+ if b == 0:
+ return a
+ return gcd(b, a%b)
+\end{lstlisting}
+ \item Check that the tests pass again
+ \end{itemize}
+\end{frame}
+
+\begin{frame}[fragile]
+ \frametitle{Document \texttt{gcd}}
+ \begin{itemize}
+ \item Undocumented function is as good as unusable
+ \item Let's add a docstring \& We have our first test!
+ \end{itemize}
+\begin{lstlisting}
+def gcd(a, b):
+ """Returns the Greatest Common Divisor of the
+ two integers passed as arguments.
+
+ Args:
+ a: an integer
+ b: another integer
+
+ Returns: Greatest Common Divisor of a and b
+ """
+ if b == 0:
+ return a
+ return gcd(b, a%b)
+\end{lstlisting}
+\end{frame}
+
+
+\begin{frame}[fragile]
+ \frametitle{Persistent Test Cases}
+ \begin{itemize}
+ \item Tests should be pre-determined and written, before the code
+ \item The file shall have multiple lines of test data
+ \item Separates the code from the tests
+ \end{itemize}
+\end{frame}
+
+\begin{frame}[fragile]
+ \frametitle{Separate \texttt{test\_gcd.py}}
+\begin{lstlisting}
+from gcd import gcd
+
+def test_gcd():
+ assert gcd(48, 64) == 16
+ assert gcd(44, 19) == 1
+
+if __name__ == '__main__':
+ test_gcd()
+\end{lstlisting}
+\end{frame}
+
+\section{Python Testing Frameworks}
+
+\begin{frame}[fragile]
+ \frametitle{Python Testing Frameworks}
+ \begin{itemize}
+ \item Testing frameworks essentially, ease the job of the user
+ \item Python provides two frameworks for testing code
+ \begin{itemize}
+ \item \texttt{unittest} framework
+ \item \texttt{doctest} module
+ \end{itemize}
+\item \texttt{nose} is a package to help test
+ \end{itemize}
+\end{frame}
+
+\subsection{\texttt{nose}}
+
+\begin{frame}[fragile]
+ \frametitle{\texttt{nose} tests}
+ \begin{itemize}
+ \item It is not easy to organize, choose and run tests scattered
+ across multiple files.
+ \item \texttt{nose} module aggregate these tests automatically
+ \item Can aggregate \texttt{unittests} and \texttt{doctests}
+ \item Allows us to pick and choose which tests to run
+ \item Helps output the test-results and aggregate them in various
+ formats
+ \item Not part of the Python distribution itself
+\begin{lstlisting}
+$ apt-get install python-nose
+\end{lstlisting} %$
+ \item Run the following command in the top level directory
+\begin{lstlisting}
+$ nosetests
+\end{lstlisting} %$
+ \end{itemize}
+\end{frame}
+
+\end{document}