Spies¶
Im Gegensatz zu Mocks umhüllen Spies die Objekte und leiten
üblicherweise alle Methodenaufrufe an das Originalobjekt weiter. Trotz seines
Namens eignet sich mock nicht nur für
Mocks: Über das Argument wraps seiner Mock-Klasse können damit auch Spies erstellt werden.
Aufrufe werden dann an das umschlossene Objekt weitergeleitet und geben dessen
tatsächliche Ergebnisse zurück, z. B.:
>>> def test_workinngday():
... spy = Mock(wraps=is_workingday, return_value=monday)
... assert is_workingday()
...
wraps stellt jedoch nur das Standardverhalten des Mocks bereit, wobei andere
Konfigurationen Vorrang haben. Wenn ihr return_value festlegt, wird das
umschlossene Objekt überhaupt nicht aufgerufen.
Wenn ihr hingegen unittest.mock.Mock.side_effect festlegt, wird
dieser anstelle des umschlossenen Objekts ausgeführt, es sei denn, er gibt
unittest.mock.DEFAULT zurück; in diesem Fall wird der Aufruf
weitergeleitet.
So können wir z. B. für die Implementierung des Löschbefehls überprüfen, ob die Tasks-CLI Fehlerbedingungen korrekt behandelt:
@app.command()
def delete(task_id: int):
"""Remove task in db with given id."""
with tasks_db() as db:
try:
db.delete_task(task_id)
except tasks.InvalidTaskId:
print(f"Error: Invalid task id {task_id}")
Um zu testen, wie die CLI mit einer Fehlerbedingung umgeht, können wir so tun,
als ob delete_task() eine Exception erzeugt, indem wir dem Mock-Objekt die
Exception dem Attribut side_effect
des Mock-Objekts zuweisen, etwa so:
def test_delete_invalid(mock_tasksdb, tasks_cli):
mock_tasksdb.delete_task.side_effect = tasks.api.InvalidTaskId
out = tasks_cli("delete 42")
assert "Error: Invalid task id 42" in out