Tutorial 5: Automated Testing / Linting

ASE WS 2023/24

Ziele

Setup

Wir arbeiten dieses Mal mit einer lokalen Python-Installation Alternativ kann man sich auch wie beim letzten Mal als Nutzer root auf einem 'disposable root server' via segfault.net einloggen.

ssh root@segfault.net # Password is 'segfault'

Achtung: Der Server ist nicht sicher - keine vertraulichen Infos/Passwörter dort eintippen

Virtual Environments in Python

Es bietet sich an, für jedes Python-Projekt ein eigenes virtual environment zu verwenden. Dazu wird in einem Unterverzeichnis des Projekts eine separate Python-Installation eingerichtet. Ein Aktivierungs-Script setzt dann für die aktuelle Shell-Session die Pfade und Umgebungsvariablen so, dass nicht mehr die systemweite Python-Installation verwendet wird, sondern die im Unterverzeichnis installierte. Wenn man mittels pip neue Pakete installiert, werden diese auch nur im virtual environment (venv) installiert.

Das folgende Code-Beispiel installiert das venv-Modul, richtet ein venv im Unterverzeichnis “.env” ein und aktiviert dieses für den Rest der Session.

$ sudo apt install python3-venv
  [...]
$ mkdir myproject; cd myproject
$ python3 -m venv .myenv 
$ source .myenv/bin/activate

Alle folgenden Befehle verwenden jetzt die Python-Installation in .myenv:

$ which python3
/home/me/myproject/.myenv/bin/python3

Meyer's Triangle Problem

Glenford J. Meyers, Corey Sandler, Tom Badgett (2015) The Art of Software Testing, John Wiley & Son, 1978/2004/2015

We want you to write a set of test cases—specific sets of data—to properly test a relatively simple program. Create a set of test data for the program—data the program must handle correctly to be considered a successful program. Here’s a description of the program:
  • The program reads three integer values from an input dialog.
  • The three values represent the lengths of the sides of a triangle.
  • The program displays a message that states whether the triangle is scalene (ungleichschenklig, ungleichseitig), isosceles (gleichschenklig), or equilateral (gleichseitig).

Let's do it by hand

Erstelle eine Datei triangle.py oder klone das Git Repo:

def triangle_shape(x, y, z):
    return None
          
def triangle_circumference(x, y, z):
    return None

def test_triangle():
     # your code
     
if __name__ == "__main__":
    import sys
    if sys.argv[1] == "--test":
        test_triangle()
    else:
    print(triangle_shape(sys.argv[1], sys.argv[1], sys.argv[3]))
  

(Achtung: es sind Syntax- und Logikfehler im Code)

Linting

Linter überprüfen den Code statisch auf Syntaxfehler und Verstöße gegen Style-Guides.

Hilfreich:

Überprüfe den Code mit den Lintern und behebe Probleme

Testing

Ergänze test_triangle um notwendige Tests. Verwende dazu assert() (siehe dieses Tutorial: https://realpython.com/python-assert-statement/)

pytest

pytest ist ein Test-Framework für Python

Beispiel:

def test_addition():
    assert(1+1==2)
   

Wenn eine Exception erwartet wird:

def test_fails():
  with pytest.raises(Exception):
      x = 1 / 0

Decorators sorgen dafür, dass Tests übersprungen werden:

@pytest.mark.skip("not yet finished")
def test_something():
    pass
    
@pytest.mark.skipif(db is None, reason = "No database available")
def test_db():
    assert(db.status == 3)

Fixtures erlauben es, benötigten Code vorher auszuführen

@pytest.fixture
def database():
  db = DataBase(123)
  yield db
  db.close()
    
def test_insert(database):
    database.insert(1)

Implementiere die notwendigen Tests und führe sie aus.

Weitere Ressourcen