Python training UGA 2017

A training to acquire strong basis in Python to use it efficiently

Pierre Augier (LEGI), Cyrille Bonamy (LEGI), Eric Maldonado (Irstea), Franck Thollard (ISTerre), Christophe Picard (LJK), Loïc Huder (ISTerre)

Testing

Why testing ? When testing ? What testing ? How testing ?

Why testing (1/4) ?

Coding without testing is dangerous (anyway, you will test somehow):

https://lesjoiesducode.fr/quand-je-dploie-en-prod-sans-tester

Why testing (3/4) ?

To get sure I conform with the specs, and/or define correct specs. Important when something went wrong ...

https://thecodinglove.com/solid-code-wrong-specs

Ease parallel dev. and code integration.

Why testing (4/4) ?

To check non regression:

  • when there is a refactor
  • when there is a critical code evolution
  • when it crashes, to select where to look for the pb

When testing ?

Historically, we use to test after coding

1) I code

2) I test

3) Go to 1)

When testing ?

TDD: test driven dev: write the test before coding

1) Define the spec

2) Write the test

3) code

4) test

5) if test not pass either go to 1), go to 2) or go to 3)

If enough ressources, the person who write the test and the one who code are different, ... but they consider the same specs!

Testing what ?

  • Unit tests

  • Functionnal tests

Testing what ?

Unit tests: test functions conforms with the specs, i.e. with the "paper" analysis !

In [ ]:
def add(a, b):
    """ add a and b and return a+b"""
    pass

Lets write the function: easy enought !

In [ ]:
def add(a, b):
    """ add a and b and return a+b"""
    return a+b

Let's write the test:

  • What do we do if a and b are not of the same type ?

  • What if a or b (or a and b) are None ?

  • What if a + b does not exists ? what should happens ?

  • What if a or b is NaN ?

All these questions has to be answered in order to write the test ... thus to write the function !

Testing what ?

Functional test: check that the code works when assembling different functions, i.e. the functions can work together !

Soure Topito

How to test ?

Different possibilities

  • just use assert !

Not detailed here:

  • use unittest from the standard lib

  • use pytest (rather standard, but need to be installed)

  • ....

 Assert ?

assert test a condition and "crashes" if the condition does not evaluate to True

In [8]:
assert 13 == 10+3
assert type(10) is int
In [10]:
assert True is False
---------------------------------------------------------------------------
AssertionError                            Traceback (most recent call last)
<ipython-input-10-bf474889e709> in <module>
----> 1 assert True is False

AssertionError: 
In [3]:
def add(arg0, arg1):
    """Print and return the sum of the two arguments (duck typing).
    assuming arg0 + arg1 is well defined. 
    """
    result = arg0 + arg1
    return result

def test_add():
    """ test add is ok with int and strings"""
    print("testing add with int ", end="")
    assert add(1, 2) == 3
    print(" .... OK")
    print("testing add ok with str", end="")
    assert add("a", "b") == "ab"
    print("... OK")
    print("test add ok")

test_add()
testing add with int  .... OK
testing add ok with str... OK
test add ok
In [3]:
add(2, 3)
result =  5
Out[3]:
5
In [4]:
add('a', 'b')
result =  ab
Out[4]:
'ab'

Do it yourself: simple function definition

Write a function that returns the sum of the first argument with twice the second argument.

In [5]:
def add_second_twice(arg0, arg1):
    """Return the sum of the first argument with twice the second one.
        Arguments should be of type that support sum and product by 
        an integer (e.g. numerical, string, list, ...)
        :param arg0: first argument
        :param arg1: second argument 
        :return: arg0 + 2 * arg1
    """
    pass


def test_add_second_twice():
    """ test add second twice"""
    print("testing add second twice with int ", end="")
    assert add_second_twice(3, 5) == 13
    print("...OK")
    print("testing add second twice with strings ", end="")
    assert add_second_twice("aa", "bb") == "aabbbb"
    print("...OK")
    print("testing add second twice with list ", end="")
    assert add_second_twice([1,2], [3,4]) == [1, 2, 3, 4, 3, 4]
    print("...OK")
    print("test add second twice OK with int, string and list")

test_add_second_twice()
testing add second twice with int 
---------------------------------------------------------------------------
AssertionError                            Traceback (most recent call last)
<ipython-input-5-84287d31dec0> in <module>
     25     print("test add second twice OK with int, string and list")
     26 
---> 27 test_add_second_twice()

<ipython-input-5-84287d31dec0> in test_add_second_twice()
     15     """ test add second twice"""
     16     print("testing add second twice with int ", end="")
---> 17     assert add_second_twice(3, 5) == 13
     18     print("...OK")
     19     print("testing add second twice with strings ", end="")

AssertionError: 

Do it yourself: simple function definition

A solution:

In [6]:
import unittest

def add_second_twice(arg0, arg1):
    """Return the sum of the first argument with twice the second one.
        Arguments should be of type that support sum and product by 
        an integer (e.g. numerical, string, list, ...)
        :param arg0: first argument
        :param arg1: second argument 
        :return: arg0 + 2 * arg1
    """
    result = arg0 + 2*arg1
    print(f'arg0 + 2*arg1 = {arg0} + 2*{arg1} = {result}')
    return result

def test_add_second_twice():
    """ test add second twice"""
    print("testing add second twice with int ", end="")
    assert add_second_twice(3, 5) == 13
    print("...OK")
    print("testing add second twice with strings ", end="")
    assert add_second_twice("aa", "bb") == "aabbbb"
    print("...OK")
    print("testing add second twice with list ", end="")
    assert add_second_twice([1,2], [3,4]) == [1, 2, 3, 4, 3, 4]
    print("...OK")
    print("test add second twice OK with int, string and list")

test_add_second_twice()
testing add second twice with int arg0 + 2*arg1 = 3 + 2*5 = 13
...OK
testing add second twice with strings arg0 + 2*arg1 = aa + 2*bb = aabbbb
...OK
testing add second twice with list arg0 + 2*arg1 = [1, 2] + 2*[3, 4] = [1, 2, 3, 4, 3, 4]
...OK
test add second twice OK with int, string and list
In [6]:
myfunc('a', 'b')
arg0 + 2*arg1 = a + 2*b = abb
Out[6]:
'abb'