\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}
