summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPrabhu Ramachandran2015-02-12 21:44:12 +0530
committerPrabhu Ramachandran2015-02-12 21:44:12 +0530
commit22870c5c31b2a8be685069b13ebde20c1bbf119c (patch)
treeadea220fc2386ce534e3787e3d492ab657d289ef
parent4766c75967e8dbf805ebd1c8a7af0f6dd0516fc0 (diff)
downloadsees-22870c5c31b2a8be685069b13ebde20c1bbf119c.tar.gz
sees-22870c5c31b2a8be685069b13ebde20c1bbf119c.tar.bz2
sees-22870c5c31b2a8be685069b13ebde20c1bbf119c.zip
Slides for classes in 2015.
Added a simpler TDD lecture set which is only based on functions and nose. Removed doctest entirely. Also added some older content on OOP from my ancient Python tutorial. Put together a slide set covering OOP and the unittest module.
-rw-r--r--slides/advanced_python/oop_unittest.tex117
-rw-r--r--slides/advanced_python/slides/oop.tex190
-rw-r--r--slides/test_driven_development/tdd_simple.tex342
3 files changed, 647 insertions, 2 deletions
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/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/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}