December, 2021 - François HU
Master of Science - EPITA
This lecture is available here: https://curiousml.github.io/
def division(a, b):
return(a/b)
division(1, 0)
--------------------------------------------------------------------------- ZeroDivisionError Traceback (most recent call last) /var/folders/55/c2kg8h2d2wnfzx5wnypmt8kr0000gn/T/ipykernel_1123/719298754.py in <module> 2 return(a/b) 3 ----> 4 division(1, 0) /var/folders/55/c2kg8h2d2wnfzx5wnypmt8kr0000gn/T/ipykernel_1123/719298754.py in division(a, b) 1 def division(a, b): ----> 2 return(a/b) 3 4 division(1, 0) ZeroDivisionError: division by zero
In order to catch the error, we insert the code likely to produce an error between the try and except keywords:
try:
# ... the program
except:
# ... what to do in case of an error
else:
# ... OPTIONAL: what to do when no errors appear
try:
division(1, 0)
except:
print("we have en error")
else:
print("no errors")
we have en error
try:
print("hello !")
print(division(1, 2))
print(division(3, 4))
print(division(2, 0))
print(division(1, 10))
except ZeroDivisionError:
print("division par zéro")
except Exception as exc:
print("unsuspected error:", exc.__class__)
print("message ", exc)
hello ! 0.5 0.75 division par zéro
def division(a, b):
if b == 0:
raise ValueError
return(a/b)
try:
division(3, 0) # error
except ValueError:
print("error type: ValueError")
error type: ValueError
make tests (in a program test_*.py
or *_test.py
by convention) to locate the source of error in a program (example package: unittest, pytest)
Example of unit test with unittest : we want to calculate the area of a circle
import numpy as np
def circle_area(r):
return np.pi*(r**2)
# test the function
message = "Area of the circle of radius r = {radius} is {area}"
for r in [2, -3, 2+5j, True, "radius"]:
A = circle_area(r)
print(message.format(radius = r, area = A))
Area of the circle of radius r = 2 is 12.566370614359172 Area of the circle of radius r = -3 is 28.274333882308138 Area of the circle of radius r = (2+5j) is (-65.97344572538566+62.83185307179586j) Area of the circle of radius r = True is 3.141592653589793
--------------------------------------------------------------------------- TypeError Traceback (most recent call last) /var/folders/55/c2kg8h2d2wnfzx5wnypmt8kr0000gn/T/ipykernel_47557/360307895.py in <module> 2 message = "Area of the circle of radius r = {radius} is {area}" 3 for r in [2, -3, 2+5j, True, "radius"]: ----> 4 A = circle_area(r) 5 print(message.format(radius = r, area = A)) /var/folders/55/c2kg8h2d2wnfzx5wnypmt8kr0000gn/T/ipykernel_47557/4063705862.py in circle_area(r) 2 3 def circle_area(r): ----> 4 return np.pi*(r**2) TypeError: unsupported operand type(s) for ** or pow(): 'str' and 'int'
import unittest
class TestCircleArea(unittest.TestCase):
def test_area(self):
# test aires lorsque rayon >= 0
self.assertAlmostEqual(circle_area(1), np.pi)
self.assertAlmostEqual(circle_area(0), 0)
self.assertAlmostEqual(circle_area(1.1), pi * 1.1**2)
#unittest.main(argv=[''], verbosity=2, exit=False);
! python -m unittest
. ---------------------------------------------------------------------- Ran 1 test in 0.000s OK
class TestCircleArea(unittest.TestCase):
def test_area(self):
# test aires lorsque rayon >= 0
self.assertAlmostEqual(circle_area(1), np.pi)
self.assertAlmostEqual(circle_area(0), 0)
self.assertAlmostEqual(circle_area(1.1), np.pi * 1.1**2)
def test_values(self):
# test aires lorsque rayon <0
self.assertRaises(ValueError, circle_area, -2)
def test_types(self):
# test aires lorsque rayon n'est pas un 'int'
self.assertRaises(ValueError, circle_area, 3+5j)
self.assertRaises(ValueError, circle_area, True)
self.assertRaises(ValueError, circle_area, "radius")
#unittest.main(argv=[''], verbosity=2, exit=False);
! python -m unittest
.FF ====================================================================== FAIL: test_types (test_my_program.TestCircleArea) ---------------------------------------------------------------------- Traceback (most recent call last): File "/Users/Faugon/Documents/3_enseignements/EPITA/python/lecture 6/test_my_program.py", line 17, in test_types self.assertRaises(ValueError, circle_area, 3+5j) AssertionError: ValueError not raised by circle_area ====================================================================== FAIL: test_values (test_my_program.TestCircleArea) ---------------------------------------------------------------------- Traceback (most recent call last): File "/Users/Faugon/Documents/3_enseignements/EPITA/python/lecture 6/test_my_program.py", line 13, in test_values self.assertRaises(ValueError, circle_area, -2) AssertionError: ValueError not raised by circle_area ---------------------------------------------------------------------- Ran 3 tests in 0.001s FAILED (failures=2)
import numpy as np
def circle_area(r):
if type(r) not in [int, float]:
raise ValueError("le rayon doit etre un entier positif")
if r < 0:
raise ValueError("le rayon ne peut pas etre negatif")
return(np.pi*(r**2))
#unittest.main(argv=[''], verbosity=2, exit=False)
! python -m unittest
... ---------------------------------------------------------------------- Ran 3 tests in 0.000s OK
Example of unit test with pytest (recommended) : we want to calculate the area of a circle
from my_program import *
import numpy as np
import pytest
def test_area():
# test aires lorsque rayon >= 0
circle_area(1) == np.pi
circle_area(0) == 0
circle_area(1.1) == np.pi * 1.1**2
def test_values():
# test aires lorsque rayon <0
with pytest.raises(ValueError):
circle_area(-2)
def test_types():
# test aires lorsque rayon n'est pas un 'int'
with pytest.raises(ValueError):
circle_area(3+5j)
circle_area(True)
circle_area("radius")
#unittest.main(argv=[''], verbosity=2, exit=False)
! py.test test_my_program.py
============================= test session starts ============================== platform darwin -- Python 3.8.0, pytest-6.2.5, py-1.11.0, pluggy-1.0.0 rootdir: /Users/Faugon/Documents/3_enseignements/EPITA/python/lecture 6 collected 3 items test_my_program.py ... [100%] ============================== 3 passed in 0.18s ===============================
OR
! py.test
============================= test session starts ============================== platform darwin -- Python 3.8.0, pytest-6.2.5, py-1.11.0, pluggy-1.0.0 rootdir: /Users/Faugon/Documents/3_enseignements/EPITA/python/lecture 6 collected 3 items test_my_program.py ... [100%] ============================== 3 passed in 0.16s ===============================
measures the number of lines of code actually executed during the execution of unit tests. (objective approx. 80%. e.g. module coverage to measure the coverage)
# or "pytest -cov test_my_program.py"
! pytest -cov
============================= test session starts ============================== platform darwin -- Python 3.8.0, pytest-6.2.5, py-1.11.0, pluggy-1.0.0 rootdir: /Users/Faugon/Documents/3_enseignements/EPITA/python/lecture 6, configfile: ov collected 3 items test_my_program.py ... [100%] ============================== 3 passed in 0.20s ===============================
OR
# or "pytest -cov test_my_program.py"
! pytest -report
============================= test session starts ============================== platform darwin -- Python 3.8.0, pytest-6.2.5, py-1.11.0, pluggy-1.0.0 rootdir: /Users/Faugon/Documents/3_enseignements/EPITA/python/lecture 6 collected 3 items test_my_program.py ... [100%] =========================== short test summary info ============================ PASSED test_my_program.py::test_area PASSED test_my_program.py::test_values PASSED test_my_program.py::test_types ============================== 3 passed in 0.16s ===============================
So all in all, here is our program and our test program: