% Tutorial Automated Testing / Linting % ASE WS 2022/23

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

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

(see presentation)

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).

Eure Aufgabe: Sammelt zu zweit alle notwendigen Testfälle, um den vollständigen Funktionsumfang des Programms zu testen (d.h. Sets an Eingabedaten und passende Ausgaben).

Erstelle eine Datei triangle.py:

def triangle(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(sys.argv[1], sys.argv[1], sys.argv[3]))
  

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

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

pytest ist ein Test-Framework für Python

  • Tests für landen in einer separaten Datei, meist auch in einem separaten Unterverzeichnis: mycode.pytests/test_mycode.py
  • pytest -v tests/_mycode.py führt alle Tests in der Datei aus.
  • Jeder Test wird als Funktion geschrieben: def test_isoceles():
  • Exception → fail

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.skipig(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)

Weitere Ressourcen