<jupyter_start><jupyter_text>Unit-TestsMit Unit-Tests kann die Funktionalität einer Python-Anwendung automatisiert getestet werden.  Das *unittest* Modul:Die Testklasse leitet von `unittest.TestCase` ab. Mit der `unittest.assertEqual()`-Methoden wird der aktuelle Wert mit einem erwarteten Wert verglichen. Weitere `.assert*()`-Methoden: *.assertTrue(x)*, *.assertFalse(x)*, *.assertIs(a, b)*, *.assertIsNone(x)*, *.assertIn(a, b)*, *.assertIsInstance(a, b)*.<jupyter_code>from math import sqrt
import unittest

class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y
        
    def move(self, dx, dy):
        self.x += dx
        self.y += dy
        
    def show(self):
        return (self.x, self.y)
    
    def distance(self, other):
        if isinstance(other, Point):
            return sqrt((self.x - other.x)**2 + (self.y - other.y)**2)
        else:
            print("We need an instance of Point to calculate the distance!")
        return 0


# test class for unit testin
class PointTest(unittest.TestCase):
    def setUp(self):
        self.p1 = Point(6, -1)
        
    def tearDown(self):
        pass
    
    def test_show(self):
        self.assertEqual(self.p1.show(), (6, -1))
        
    def test_move(self):
        self.assertEqual(self.p1.show(), (6, -1))
        self.p1.move(-2, 5)
        self.assertEqual(self.p1.show(), (4, 4))
        
    def test_distance(self):
        p2 = Point(3, 3)
        self.assertEqual(self.p1.distance(p2), 5.0)        
      
unittest.main(argv=[''], verbosity=2, exit=False)<jupyter_output><empty_output><jupyter_text>Testen mit *doctest*:Bei `doctest` wird eine Testanweisung im *docstring* definiert (mit `>>>`) und ausgewertet.<jupyter_code>from math import sqrt
import doctest

class Point:    
    def __init__(self, x, y):
        self.x = x
        self.y = y
        
    def move(self, dx, dy):
        """
        >>> p = Point(6, -1)
        >>> p.move(-2, 5)
        >>> p.show()
        (4, 4)
        """
        self.x += dx
        self.y += dy
        
    def show(self):
        """
        >>> p = Point(6, -1)
        >>> p.show()
        (6, -1)
        """        
        return (self.x, self.y)
    
    def distance(self, other):
        """
        >>> p1 = Point(6, -1)
        >>> p2 = Point(3, 3)
        >>> p1.distance(p2)
        5.0
        """
        if isinstance(other, Point):
            return sqrt((self.x - other.x)**2 + (self.y - other.y)**2)
        else:
            print("We need an instance of Point to calculate the distance!")
        return 0
    
doctest.testmod()<jupyter_output><empty_output><jupyter_text>Das *py.test* Modul:Das *pytest*-Modul ist ähnlich dem *unittest*-Modul. Es muss mit *PIP* installiert werden   In *pytest* beginnt jede Methode mit `test_`. Mit dem `assert` Schlüsselwort wird der erwartete Wert mit dem aktuellen Wert verglichen.<jupyter_code>%load_ext ipython_pytest
%%pytest
from math import sqrt

class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y
        
    def move(self, dx, dy):
        self.x += dx
        self.y += dy
        
    def show(self):
        return (self.x, self.y)
    
    def distance(self, other):
        if isinstance(other, Point):
            return sqrt((self.x - other.x)**2 + (self.y - other.y)**2)
        else:
            print("We need an instance of Point to calculate the distance!")
        return 0

# unit tests using pyest
def test_show():
    p = Point(6, -1)
    assert p.show() == (6, -1)

def test_move():
    p = Point(6, -1)
    p.move(-2, 5)
    assert p.show() == (4, 4)
    
def test_distance():
    p1 = Point(6, -1)
    p2 = Point(3, 3)
    assert p1.distance(p2) == 5.0<jupyter_output><empty_output><jupyter_text>Stellt `assert` einen Fehler fest, wird eine ausführliche Meldung ausgegeben.Üblicherweise befindet die Funktionlität in einem Modul (z.B. *point.py*), während für die Tests ein zweites Modul erzeugt wird (z.B. *test_point.py*). Mit dem Befehl `pytest` werden die Module *test_???.py* im aktuellen Verzeichnis ausgefüht, d.h. es werden alle Funktionen in solchen Modueln, welche mit *test_* beginnen, aufgerufen.Wird *pytest* auf der Kommandozeile aufgerufen, können Flags angefügt werden (siehe [pytest - Usage and Invocations](https://docs.pytest.org/en/stable/usage.html)):- *pytest -x*: nach dem ersten Fehler stoppen- *pytest --lf*: den Test mit dem letzten Fehler aufrufen- *pytest --pdb*: in den Python-Debugger (PDB) wechseln, wenn ein Fehler gefunden wird  Arbeiten mit *pytest fixtures*Im Test der `Point`-Klasse wurde in jedem Test eine `Point`-Instanz erzeugt, meist mit den gleichen Werten. Mit einer *Fixture* kann dieser Prozess vereinfacht werden. Eine Fixture ist eine Methode, welche mit `@pytest.fixture` annotiert ist und verwendet werden kann, um die Erzeugung von Testobjekten zu vereinfachen.  Die Fixture muss den Testmethoden als Parameter übergeben werden.<jupyter_code>%%pytest
from math import sqrt
import pytest

class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y
        
    def move(self, dx, dy):
        self.x += dx
        self.y += dy
        
    def show(self):
        return (self.x, self.y)
    
    def distance(self, other):
        if isinstance(other, Point):
            return sqrt((self.x - other.x)**2 + (self.y - other.y)**2)
        else:
            print("We need an instance of Point to calculate the distance!")
        return 0
    
@pytest.fixture
def pt():
    return Point(6, -1)

def test_show(pt):
    assert pt.show() == (6, -1)

def test_move(pt):
    pt.move(-2, 5)
    assert pt.show() == (4, 4)
    
def test_distance(pt):
    other = Point(3, 3)
    assert pt.distance(other) == 5.0<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.13187003110957485, 'fraction_numerical': 0.015036294503975112, 'mean_word_length': 2.4508050089445437, 'pattern_counts': {'":': 0, '<': 17, '<?xml version=': 0, '>': 44, 'https://': 1, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '4', 'dir': 'jupyter-structured-clean-dedup', 'id': '368799', 'license': 'CC0-1.0', 'n_tokens_mistral': 2022, 'n_tokens_neox': 2010, 'n_words': 574, 'path': 'ws4/Unit-Tests.ipynb', 'repo_name': 'eth-its/Python-for-SysAdmins', 'size': '5786'}