\item{Let's get started, I encourage everyone to pull out their laptops and follow along.}
\item{We will test A1 from last year, which was introduced in the past tutorials}
\item{Don't be afraid to ask any questions!}
\end{itemize}
\end{frame}
\begin{frame}[fragile]
\frametitle{Create our first unit test file}
\begin{itemize}
\item{To start, create a new Python file called test\_circles.py in the same directory of our file that we want to test}
\item{You can do this from the command line or any text editor of your choice. Don't be afraid to ask any questions!}
\end{itemize}
\end{frame}
\begin{frame}[fragile]
\frametitle{Create our first test template}
\begin{itemize}
\item{To start with our unit test, follow this template:}
\end{itemize}
\begin{lstlisting}[language=Python]
import pytest
class TestCircles:
\end{lstlisting}
\begin{enumerate}
\item{Import the pytest library}
\item{Write a unit testing class starting with the word \texttt{Test}}
\end{enumerate}
\end{frame}
\begin{frame}[fragile]
\frametitle{What is Assert?}
\begin{itemize}
\item{ Wikipedia: \say{... an assertion is a statement that a predicate (Boolean-valued function, i.e. a true-false expression) is expected to always be true at that point in the code. If an assertion evaluates to false at run time, an assertion failure results, which typically causes the program to crash, or to throw an assertion exception.}}
\item{Basically, if whatever follows assert is true, it will continue. Otherwise the test will fail and stop running.}
\end{itemize}
\end{frame}
\begin{frame}[fragile]
\frametitle{Example of Assert?}
\begin{itemize}
\item{To assert something to be true, you can write}
\begin{lstlisting}[language=Python]
assert <true statement>
\end{lstlisting}
\item{To assert something to be false, you can write}
\begin{lstlisting}[language=Python]
assert not <false statement>
\end{lstlisting}
\end{itemize}
\end{frame}
\begin{frame}[fragile]
\frametitle{Writing our first test}
\begin{lstlisting}[language=Python]
import pytest
from CircleADT import *
class TestCircles:
def test_xcoord_are_equal(self):
circle = CircleT(1,2,3)
assert circle.xcoord() == 1
def test_xcoord_are_not_equal(self):
circle = CircleT(1,2,3)
assert not (circle.xcoord() == 2)
# or `assert circle.xcoord() != 2'
\end{lstlisting}
\end{frame}
\begin{frame}[fragile]
\frametitle{Running our first test}
\begin{itemize}
\item{Run this command in your command prompt inside the folder of your test file: \texttt{pytest test\_circles.py}}
\item{To run all tests within the directory, just run \texttt{pytest}. It will search for all files starting with "test\_" and run all methods starting with "test\_"}
\item{\texttt{nan\_ok}: facilitates comparing arrays that use NaN to mean "no data"}
\end{itemize}
\item{By default, \texttt{approx} considers numbers within a relative tolerance of 1e-6 and absolute tolerance of 1e-12 of its expected value to be equal. }
\end{itemize}
\begin{lstlisting}[language=Python, escapechar=!]
>>> 1.0001 == approx(1)
False
>>> 1.0001 == approx(1, rel=1e-3)
True
>>> 1.0001 == approx(1, abs=1e-3)
True
\end{lstlisting}
\end{frame}
\begin{frame}[fragile]
\frametitle{Redundant code in tests}
\begin{lstlisting}[language=Python, escapechar=!]
import pytest
from CircleADT import *
class TestCircles:
def test_xcoord_are_equal(self):
!\colorbox{yellow}{circle = CircleT(1,2,3)}!
assert circle.xcoord() == 1
def test_xcoord_are_not_equal(self):
!\colorbox{yellow}{circle = CircleT(1,2,3)}!
assert not circle.xcoord() == 1
\end{lstlisting}
\end{frame}
\begin{frame}[fragile]
\frametitle{Cleaned up code}
\begin{lstlisting}[language=Python, escapechar=!]
import pytest
from CircleADT import *
class TestCircles:
def setup_method(self, method):
self.circle = CircleT(1,2,3)
def teardown_method(self, method):
self.circle = None
def test_xcoord_are_equal(self):
assert self.circle.xcoord() == 1
def test_xcoord_are_not_equal(self):
assert not self.circle.xcoord() == 2
\end{lstlisting}
\end{frame}
\begin{frame}[fragile]
\frametitle{Setup and Teardown}
\begin{itemize}
\item{\texttt{setup\_class(cls)}}
\begin{itemize}
\item{setup any state specific to the execution of the given class}
\end{itemize}
\item{\texttt{teardown\_class(cls)}}
\begin{itemize}
\item{teardown any state that was previously setup with a call to \texttt{setup\_class}.}
\end{itemize}
\item{\texttt{setup\_method(self, method)}}
\begin{itemize}
\item{setup any state tied to the execution of the given method in a class. \texttt{setup\_method} is invoked for every test method of a class.}
\end{itemize}
\item{\texttt{teardown\_method(self, method)}}
\begin{itemize}
\item{teardown any state that was previously setup with a \texttt{setup\_method} call.}
\end{itemize}
\end{itemize}
\end{frame}
\begin{frame}[fragile]
\frametitle{Asserting about exceptions}
\begin{itemize}
\item{It is very important in unit testing to check for edge cases and behaviour in the case of unexpected input.}
\item{If a function raises an exception in some cases, you should include those cases in your unit testing as well.}
\item{You can do so by using a context manager called pytest.raises.}
\end{itemize}
\begin{lstlisting}[language=Python, escapechar=!]
import pytest
def test_zero_division():
with pytest.raises(ZeroDivisionError):
1 / 0
\end{lstlisting}
\end{frame}
\begin{frame}[fragile]
\frametitle{Asserting about exceptions}
\begin{itemize}
\item{If an exception is not raised in a pytest.raises block, the test will fail.}
\end{itemize}
\begin{lstlisting}[language=Python, escapechar=!]
import pytest
def test_zero_division():
with pytest.raises(ZeroDivisionError):
2 / 1
\end{lstlisting}
\begin{itemize}
\item{If you run this test, it will give the result:}