Sitemap
Grat

Grat

PHPUnit | stubs vs mocks

2 min readAug 20, 2026

PHPUnit hat in seinen Anfängen nur Mocks unterstützt. Doch seit einigen Releases werden auch Stubs unterstützt, und erhalten immer besseren Support. Inzwischen muss expilizit darauf geachtet werden, ob ein Stub oder ein Mock erstellt wird.

Ein Grund sich das einmal im Detail anzuschauen, was der Unterschied zwischen Stub und Mock ist.

“Damals” richtig:

$this->createMock('Foo::class');
$this->method('bar')
->willReturn([]);

Aber was ist hier inzwischen der Fehler?

Ein Mock hat immer Voraussetzungen. Z.B. ein Mock muss mindestens 1 Mal aufgerufen werden, oder die Funktion muss mit Parameter XY aufgerufen werden.

Immer wenn es heißt: eine Funktion wird aufgerufen, egal wie, und gibt XY zurück, dann ist es ein Stub. Es gibt keine Voraussetzungen das etwas zurückgegeben wird. Es wird eine Funktion definiert und es ist egal ob und wie sie aufgerufen wird.

$this->createStub('Foo::class');
$this->method('bar')
->willReturn([]);

Ein Mock dagegen, der mindestens einmal aufgerufen werden soll ist:

$this->createMock('Foo::class');
$this->expects($this->atLeastOnce())
->method('bar')
->willReturn([]);

D.h. die Funktion muss mindestens 1 Mal aufgerufen werden, sonst schlägt der Test fehl.

Get Grat’s stories in your inbox

Join Medium for free to get updates from this writer.

Hier ein Beispiel, wenn die Funktion mit einem Parameter aufgerufen werden muss:

$this->createMock('Foo::class');
$this->method('bar')
->with('my-parameter')
->willReturn([])

In Kombination von beiden Angaben ergibt sich:

$this->createMock('Foo::class');
$this->expects($this->atLeastOnce())
->method('bar')
->with('my-parameter')
->willReturn([])

Am aller wichtigsten hierbei ist allerdings: es sollte immer nur das aktiv getestet werden, was auch der Test vorsieht und den Test rechtfertigt.

Z.B. soll geprüft werden ob beim Speichern von User-Daten der Audit-Log geschrieben wird.

Falscher Test:

$this->createMock('AuditLog::class');
$this->expects($this->atLeastOnce())
->method('log')
->with('my-parameter')
->willReturn([])

$this->assertSame('success', $response['save'])

Hier wird geprüft ob, der Audit-Log verwendet wird, und zusätzlich ob die Rückgabe korrekt ist. Aber der Audit-Log ist gemockt, d.h. die Rückgabe wird durch den Mock definiert. Das Prüfen vom Response gibt somit kein Mehrwert.
Ob der Audit-Log aufgerufen wird, dafür reicht der Mock für das Audit-Log, weil dieser expilizit prüft, das er mindestens 1 Mal aufgerufen wird.
Was der Service zurück gibt ist dabei nicht relevant.

Ob der Response richtig ist, sollte natürlich auch geprüft werden, dann über einen eigenen Test

--

--