Mock

Mock-Objekte fördern Tests, die auf dem Verhalten von Objekten basieren. Die Python-Bibliothek mock ermöglicht euch, Teile des zu testenden Systems durch Scheinobjekte zu ersetzen und Aussagen über deren Verwendung zu treffen.

Installation

mock ist seit Python 3.3 in der Python-Standardbibliothek enthalten. Für ältere Versionen von Python könnt ihr sie installieren mit:

$ bin/python -m pip install mock

Beispiel

In unserem Beispiel wollen wir prüfen, ob die Arbeitstage von Montag bis Freitag korrekt ermittelt werden.

  1. Zunächst importieren wir datetime und Mock:

[1]:
from datetime import datetime
from unittest.mock import Mock
  1. Dann definieren wir zwei Testtage:

[2]:
monday = datetime(year=2021, month=10, day=11)
saturday = datetime(year=2021, month=10, day=16)
  1. Nun definieren wir eine Methode zur Überprüfung der Arbeitstage, wobei die datetime-Bibliothek von Python Montage als 0 und Sonntage als 6 behandelt:

[3]:
def is_workingday():
    today = datetime.today()
    return (0 <= today.weekday() < 5)
  1. Dann mocken wir datetime:

[4]:
datetime = Mock()
  1. Schließlich testen wir unsere beiden Mock-Objekte:

[5]:
datetime.today.return_value = monday
assert is_workingday()
[6]:
datetime.today.return_value = saturday
assert not is_workingday()
[7]:
datetime.today.return_value = monday
assert not is_workingday()
---------------------------------------------------------------------------
AssertionError                            Traceback (most recent call last)
Cell In[7], line 2
      1 datetime.today.return_value = monday
----> 2 assert not is_workingday()

AssertionError:

mock.ANY

Mit mock.ANY könnt ihr prüfen, ob ein Wert überhaupt vorhanden ist, ohne einen genauen Wert prüfen zu müssen:

[8]:
from unittest.mock import ANY


mock = Mock(return_value=None)
mock("foo", bar=object())
mock.assert_called_once_with("foo", bar=ANY)

Hinweis:

In test_report.py des OpenStack Containerdienstes Zun findet ihr weitere praktische Beispiele für ANY.

patch-Dekorator

Um Mock-Klassen oder Objekte zu erzeugen, kann der patch-Dekorator verwendet werden. In den folgenden Beispielen wird die Ausgabe von os.listdir gemockt. Dazu muss die Datei example.txt nicht im Verzeichnis vorhanden sein:

[9]:
import os

from unittest import mock
[10]:
@mock.patch("os.listdir", mock.MagicMock(return_value="example.txt"))
def test_listdir():
    assert "example.txt" == os.listdir()


test_listdir()

Alternativ kann der Rückgabewert auch separat definiert werden:

[11]:
@mock.patch("os.listdir")
def test_listdir(mock_listdir):
    mock_listdir.return_value = "example.txt"
    assert "example.txt" == os.listdir()


test_listdir()

Hinweis:

Mit responses könnt ihr Mock-Objekte für die httpx-Bibliothek erstellen.