diff options
Diffstat (limited to 'slides')
-rw-r--r-- | slides/advanced_python/advanced_py.tex | 10 | ||||
-rw-r--r-- | slides/advanced_python/oop_unittest.tex | 117 | ||||
-rw-r--r-- | slides/advanced_python/slides/modules.tex | 66 | ||||
-rw-r--r-- | slides/advanced_python/slides/oop.tex | 190 | ||||
-rw-r--r-- | slides/basic_python/python_part2.tex | 291 | ||||
-rw-r--r-- | slides/test_driven_development/tdd_simple.tex | 342 |
6 files changed, 948 insertions, 68 deletions
diff --git a/slides/advanced_python/advanced_py.tex b/slides/advanced_python/advanced_py.tex index b15419e..0be43d6 100644 --- a/slides/advanced_python/advanced_py.tex +++ b/slides/advanced_python/advanced_py.tex @@ -50,4 +50,14 @@ showstringspaces=false, keywordstyle=\color{blue}\bfseries} \include{slides/scipy} \include{slides/modules} +\section{Other packages} + +\begin{frame}{Very useful packages} + \begin{itemize} + \item \url{http://ipython.org/} + \item \url{http://sympy.org/} + \item \url{http://pandas.pydata.org/} + \end{itemize} +\end{frame} + \end{document} diff --git a/slides/advanced_python/oop_unittest.tex b/slides/advanced_python/oop_unittest.tex new file mode 100644 index 0000000..b8e21bf --- /dev/null +++ b/slides/advanced_python/oop_unittest.tex @@ -0,0 +1,117 @@ +\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: OOP and more testing} +\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} + +\include{slides/oop} + + +\section{\texttt{unittest} framework} + +\begin{frame}[fragile] + \frametitle{\texttt{unittest}} + \begin{itemize} + \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}} + \begin{itemize} + \item Subclass the \texttt{TestCase} class in \texttt{unittest} + \item Place all the test code as methods of this class + \item Place the code in \texttt{test\_gcd.py} + \end{itemize} +\end{frame} + +\begin{frame}[fragile,allowframebreaks] + \frametitle{\texttt{test\_gcd.py}} +\small +\begin{lstlisting} +import gcd +import unittest + +class TestGcdFunction(unittest.TestCase): + def setUp(self): + # Called before each test case. + print "In setUp" + + def tearDown(self): + print "In tearDown" + + def test_gcd(self): + self.assertEqual(gcd.gcd(45, 5), 5) + self.assertEqual(gcd.gcd(45, 5), 5) + + def test_gcd_correctly_handles_floats(self): + # Write appropriate tests here. + pass + +if __name__ == '__main__': + unittest.main() +\end{lstlisting} +\end{frame} + +\begin{frame}[fragile] + \frametitle{\texttt{test\_gcd.py}} + \begin{itemize} + \item \texttt{setUp} -- called before every \texttt{test\_*} method + \item \texttt{tearDown} -- called after every test + \item \texttt{setUp} and \texttt{tearDown} -- useful to perform common + operations, make a temporary directory, delete it when done etc. + \item \texttt{test\_gcd} -- actual test code + \item \texttt{assertEqual} -- compare actual result with expected one + \item Also see: \url{docs.python.org/2.7/library/unittest.html} + \end{itemize} +\end{frame} + + + +\end{document} diff --git a/slides/advanced_python/slides/modules.tex b/slides/advanced_python/slides/modules.tex index d6de640..707c3b3 100644 --- a/slides/advanced_python/slides/modules.tex +++ b/slides/advanced_python/slides/modules.tex @@ -94,70 +94,4 @@ \end{lstlisting} \end{frame} -\section{Writing modules} - -\begin{frame}[fragile] - \frametitle{GCD script} - \begin{itemize} - \item Function that computes gcd of two numbers - \item Save it as \texttt{gcd\_script.py} - \end{itemize} - \begin{lstlisting} - def gcd(a, b): - while b: - a, b = b, a%b - return a - \end{lstlisting} - \begin{itemize} - \item Also add the tests to the file - \end{itemize} - \begin{lstlisting} - if gcd(40, 12) == 4 and gcd(12, 13) == 1: - print "Everything OK" - else: - print "The GCD function is wrong" - \end{lstlisting} - \begin{lstlisting} - $ python gcd_script.py - \end{lstlisting} % $ -\end{frame} - -\begin{frame}[fragile] - \frametitle{Python path} - \begin{itemize} - \item In IPython type the following - \end{itemize} - \begin{lstlisting} - import sys - sys.path - \end{lstlisting} - \begin{itemize} - \item List of locations where python searches for a module - \item \texttt{import sys} -- searches for file \texttt{sys.py} or - dir \texttt{sys} in all these locations - \item So, our own modules can be in any one of the locations - \item Current working directory is one of the locations - \end{itemize} -\end{frame} - -\begin{frame}[fragile] - \frametitle{\texttt{\_\_name\_\_}} - \begin{lstlisting} - import gcd_script - \end{lstlisting} - \begin{itemize} - \item The import is successful - \item But the test code, gets run - \item Add the tests to the following \texttt{if} block - \end{itemize} - \begin{lstlisting} - if __name__ == "__main__": - \end{lstlisting} - \begin{itemize} - \item Now the script runs properly - \item As well as the import works; test code not executed - \item \texttt{\_\_name\_\_} is local to every module and is equal - to \texttt{\_\_main\_\_} only when the file is run as a script. - \end{itemize} -\end{frame} diff --git a/slides/advanced_python/slides/oop.tex b/slides/advanced_python/slides/oop.tex index bdb983c..e1e96f8 100644 --- a/slides/advanced_python/slides/oop.tex +++ b/slides/advanced_python/slides/oop.tex @@ -13,6 +13,190 @@ \end{frame} \begin{frame}[fragile] + \frametitle{Classes: the big picture} + \begin{itemize} + \item Lets you create new data types + \item Class is a template for an object belonging to that class + \item Note: in Python a class is also an object + \item Instantiating a class creates an instance (an object) + \item An instance encapsulates the state (data) and behavior + (methods) + \item Allows you to define an inheritance hierarchy + \begin{itemize} + \item ``A Honda car \alert{is a} car.'' + \item ``A car \alert{is an} automobile.'' + \item ``A Python \alert{is a} reptile.'' + \end{itemize} + \item Programmers need to think OO + \end{itemize} +\end{frame} + +\begin{frame}[fragile] + \frametitle{Classes: what's the big deal?} + \begin{itemize} + \item Lets you create objects that mimic a real problem being + simulated + \item Makes problem solving more natural and elegant + \item Easier to create code + \item Allows for code-reuse + \item Polymorphism + \end{itemize} +\end{frame} + +\begin{frame}[fragile] + \frametitle{Class definition and instantiation} + \begin{itemize} + \item Class definitions when executed create class objects + \item Instantiating the class object creates an instance of the + class + \end{itemize} +\footnotesize +\begin{lstlisting} +class Foo(object): + pass +# class object created. + +# Create an instance of Foo. +f = Foo() +# Can assign an attribute to the instance +f.a = 100 +print f.a +100 +\end{lstlisting} +\end{frame} + +\begin{frame}[fragile] + \frametitle{Classes \ldots} + \begin{itemize} + \item All attributes are accessed via the \texttt{object.attribute} + syntax + \item Both class and instance attributes are supported + \item \emph{Methods} represent the behavior of an object: crudely + think of them as functions ``belonging'' to the object + \item All methods in Python are ``virtual'' + \item Inheritance through subclassing + \item Multiple inheritance is supported + \item No special public and private attributes: only good + conventions + \begin{itemize} + \item \verb+object.public()+: public + \item \verb+object._private()+ \& \verb+object.__priv()+: + non-public + \end{itemize} + \end{itemize} +\end{frame} + +\begin{frame}[fragile] + \frametitle{Classes: examples} +\begin{lstlisting} +class MyClass(object): + """Example class (this is the class docstring).""" + i = 12345 # A class attribute + def f(self): + """This is the method docstring""" + return 'hello world' + +>>> a = MyClass() # creates an instance +>>> a.f() +'hello world' +>>> # a.f() is equivalent to MyClass.f(a) +... # This also explains why f has a 'self' argument. +... MyClass.f(a) +'hello world' +\end{lstlisting} +\end{frame} + +\begin{frame}[fragile] + \frametitle{Classes (continued)} + \begin{itemize} + \item \texttt{self} is \alert{conventionally} the first argument for a + method + \item In previous example, \texttt{a.f} is a method object + \item When \texttt{a.f} is called, it is passed the instance \texttt{a} as + the first argument + \item If a method called \verb+__init__+ exists, it is called when + the object is created + \item If a method called \verb+__del__+ exists, it is called before + the object is garbage collected + \item Instance attributes are set by simply ``setting'' them in + \texttt{self} + \item Other special methods (by convention) like \verb+__add__+ let + you define numeric types: + {\footnotesize \url{https://docs.python.org/2.7/reference/datamodel.html} + } + \end{itemize} +\end{frame} + +\begin{frame}[fragile] + \frametitle{Classes: examples} +\begin{lstlisting} +class Bag(MyClass): # Shows how to derive classes + def __init__(self): # called on object creation. + self.data = [] # an instance attribute + def add(self, x): + self.data.append(x) + def addtwice(self, x): + self.add(x) + self.add(x) +>>> a = Bag() +>>> a.f() # Inherited method +'hello world' +>>> a.add(1); a.addtwice(2) +>>> a.data +[1, 2, 2] +\end{lstlisting} +\end{frame} + +\begin{frame}[fragile] + \frametitle{Derived classes} + \begin{itemize} + \item Call the parent's \verb+__init__+ if needed + \item If you don't need a new constructor, no need to define it in subclass + \item Can also use the \verb+super+ built-in function + \end{itemize} +\begin{lstlisting} +class AnotherBag(Bag): + def __init__(self): + # Must call parent's __init__ explicitly + Bag.__init__(self) + # Alternatively use this: + super(AnotherBag, self).__init__() + # Now setup any more data. + self.more_data = [] +\end{lstlisting} +\end{frame} + +\begin{frame}[fragile] + \frametitle{Classes: polymorphism} +\begin{lstlisting} +class Drawable(object): + def draw(self): + # Just a specification. + pass +\end{lstlisting} +\mode<presentation>{\pause} +\begin{lstlisting} +class Square(Drawable): + def draw(self): + # draw a square. +class Circle(Drawable): + def draw(self): + # draw a circle. +\end{lstlisting} +\end{frame} +\begin{frame}[fragile] + \frametitle{Classes: polymorphism} +\begin{lstlisting} +class Artist(Drawable): + def draw(self): + for obj in self.drawables: + obj.draw() +\end{lstlisting} +\end{frame} + + + +\begin{frame}[fragile] \frametitle{Example: Managing Talks} \begin{itemize} \item A list of talks at a conference @@ -191,8 +375,10 @@ class Tutorial(Talk): """A class for the tutorials.""" - def __init__(self, speaker, title, tags, handson=True): - Talk.__init__(self, speaker, title, tags) + def __init__(self, speaker, title, tags, + handson=True): + Talk.__init__(self, speaker, title, + tags) self.handson = handson def is_handson(self): diff --git a/slides/basic_python/python_part2.tex b/slides/basic_python/python_part2.tex new file mode 100644 index 0000000..9faddfd --- /dev/null +++ b/slides/basic_python/python_part2.tex @@ -0,0 +1,291 @@ +\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{More Basic Python} +\author[FOSSEE] {FOSSEE} +\institute[IIT Bombay] {Department of Aerospace Engineering\\IIT Bombay} +\date []{} + +\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{Using Python modules} + +\begin{frame}[fragile] + \frametitle{\texttt{hello.py}} + \begin{itemize} + \item Script to print `hello world' -- \texttt{hello.py} + \end{itemize} + \begin{lstlisting} + print "Hello world!" + \end{lstlisting} + \begin{itemize} + \item We have been running scripts from IPython + \end{itemize} + \begin{lstlisting} + In[]: %run -i hello.py + \end{lstlisting} + \begin{itemize} + \item Now, we run from the shell using python + \end{itemize} + \begin{lstlisting} + $ python hello.py + \end{lstlisting} +\end{frame} + + +\begin{frame} + \frametitle{Modules} + \begin{itemize} + \item Organize your code + \item Collect similar functionality + \item Functions, classes, constants, etc. + \end{itemize} +\end{frame} + +\begin{frame} + \frametitle{Modules} + \begin{itemize} + \item Define variables, functions and classes in a file with a + \texttt{.py} extension + \item This file becomes a module! + \item The \texttt{import} keyword ``loads'' a module + \item One can also use: + \mbox{\texttt{from module import name1, name2, name2}}\\ + where \texttt{name1} etc. are names in the module, ``module'' + \item \texttt{from module import *} \ --- imports everything from module, + \alert{use only in interactive mode} + \item File name should be valid variable name + \end{itemize} +\end{frame} + +\begin{frame}[fragile] + \frametitle{Modules: example} + \begin{lstlisting} +# --- foo.py --- +some_var = 1 +def fib(n): # write Fibonacci series up to n + """Print a Fibonacci series up to n.""" + a, b = 0, 1 + while b < n: + print b, + a, b = b, a+b +# EOF + \end{lstlisting} +\end{frame} + +\begin{frame}[fragile] + \frametitle{Modules: example} + \begin{lstlisting} +>>> import foo +>>> foo.fib(10) +1 1 2 3 5 8 +>>> foo.some_var +1 + \end{lstlisting} +\end{frame} + + +\begin{frame}[fragile] + \frametitle{Python path} + \begin{itemize} + \item In IPython type the following + \end{itemize} + \begin{lstlisting} + import sys + sys.path + \end{lstlisting} + \begin{itemize} + \item List of locations where python searches for a module + \item \texttt{import sys} -- searches for file \texttt{sys.py} or + dir \texttt{sys} in all these locations + \item So, our own modules can be in any one of the locations + \item Current working directory is one of the locations + \item Can also set \texttt{PYTHONPATH} env var + \end{itemize} +\end{frame} + + +\begin{frame}[fragile] + \frametitle{Another example: GCD script} + \begin{itemize} + \item Function that computes gcd of two numbers + \item Save it as \texttt{gcd\_script.py} + \end{itemize} + \begin{lstlisting} + def gcd(a, b): + while b: + a, b = b, a%b + return a + \end{lstlisting} + \begin{itemize} + \item Also add the tests to the file + \end{itemize} + \begin{lstlisting} + if gcd(40, 12) == 4 and gcd(12, 13) == 1: + print "Everything OK" + else: + print "The GCD function is wrong" + \end{lstlisting} + \begin{lstlisting} + $ python gcd_script.py + \end{lstlisting} % $ +\end{frame} + +\begin{frame}[fragile] + \frametitle{\texttt{\_\_name\_\_}} + \begin{lstlisting} + import gcd_script + \end{lstlisting} + \begin{itemize} + \item The import is successful + \item But the test code, gets run + \item Add the tests to the following \texttt{if} block + \end{itemize} + \begin{lstlisting} + if __name__ == "__main__": + \end{lstlisting} + \begin{itemize} + \item Now the script runs properly + \item As well as the import works; test code not executed + \item \texttt{\_\_name\_\_} is local to every module and is equal + to \texttt{\_\_main\_\_} only when the file is run as a script. + \end{itemize} +\end{frame} + + +\begin{frame}[fragile] + \frametitle{Stand-alone scripts} +Consider a file \texttt{f.py}: +\footnotesize +\begin{lstlisting} +#!/usr/bin/env python +"""Module level documentation.""" +# First line tells the shell that it should use Python +# to interpret the code in the file. +def f(): + print "f" + +# Check if we are running standalone or as module. +# When imported, __name__ will not be '__main__' +if __name__ == '__main__': + # This is not executed when f.py is imported. + f() +\end{lstlisting} +\end{frame} + + +\section{Exceptions} + +\begin{frame}{Motivation} + \begin{itemize} + \item How do you signal errors to a user? + \end{itemize} +\end{frame} + +\begin{frame} + \frametitle{Exceptions} + \begin{itemize} + \item Python's way of notifying you of errors + \item Several standard exceptions: \texttt{SyntaxError}, \texttt{IOError} + etc. + \item Users can also \texttt{raise} errors + \item Users can create their own exceptions + \item Exceptions can be ``caught'' via \texttt{try/except} blocks + \end{itemize} +\end{frame} + +\begin{frame}[fragile] + \frametitle{Exception: examples} +\begin{lstlisting} +>>> 10 * (1/0) +Traceback (most recent call last): + File "<stdin>", line 1, in ? +ZeroDivisionError: integer division or modulo by zero +>>> 4 + spam*3 +Traceback (most recent call last): + File "<stdin>", line 1, in ? +NameError: name 'spam' is not defined +>>> '2' + 2 +Traceback (most recent call last): + File "<stdin>", line 1, in ? +TypeError: cannot concatenate 'str' and 'int' objects +\end{lstlisting} +\end{frame} + +\begin{frame}[fragile] + \frametitle{Exception: examples} +\begin{lstlisting} +>>> while True: +... try: +... x = int(raw_input("Enter a number: ")) +... break +... except ValueError: +... print "Invalid number, try again..." +... +>>> # To raise exceptions +... raise ValueError("your error message") +Traceback (most recent call last): + File "<stdin>", line 2, in ? +ValueError: your error message +\end{lstlisting} +\end{frame} + +\begin{frame}[fragile] + \frametitle{Exception: try/finally} +\begin{lstlisting} +>>> while True: +... try: +... x = open("my_data.txt") +... lines = x.readlines() +... # Process the data from the file. +... value = int(line[0]) +... except ValueError: +... print "Invalid file!" +... finally: +... print "All good!" +... +\end{lstlisting} +\end{frame} + + + +\end{document} 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} |