# Unit Tests mit dem OXID Framework

**URL:** <https://forum.oxid-esales.com/t/unit-tests-mit-dem-oxid-framework/94723>\
**Category:** Blog Posts über OXID\
**Tags:** entwicklung-dev\
**Created:** [January 21, 2019, 8:54pm UTC](https://forum.oxid-esales.com/t/unit-tests-mit-dem-oxid-framework/94723 "2019-01-21T20:54:46Z")\
**Posts on this page:** 2\
**Page:** 1

<div class="post-metadata">

**Author:** ![CodeCommerce](https://forum.oxid-esales.com/letter_avatar_proxy/v4/letter/c/e19adc/32.png) [@CodeCommerce](https://forum.oxid-esales.com/u/CodeCommerce)\
**Post date:** [January 21, 2019, 8:54pm UTC](https://forum.oxid-esales.com/t/unit-tests-mit-dem-oxid-framework/94723/1 "2019-01-21T20:54:47Z")

</div>

Keine Lust zu lesen? Wir haben für dich ein Tutorial Video bereitgestellt welches du unten findest.

## Einrichtung OXID VM & Projekt

Du hast bereits eine Funktionierende Installation von OXID Version 6? Dann kannst du diesen Abschnitt überspringen.

Für dieses Tutorial benötigst du die Version 6 von OXID eSales. Du kannst das Projekt in jeder Anwendung aufsetzen – sei es Docker, Mamp, Xampp oder auch Vagrant.

OXID eSales bietet eine Virtual Machine für die OXID Version 6 auf Github an.

Zu finden ist Sie unter [https://github.com/OXID-eSales/oxvm\_eshop](https://github.com/OXID-eSales/oxvm_eshop).

Bitte richte dich nach den Installations-Instruktionen die auf der Github Seite angegeben wurden.

Nachdem die Installation der VM fertiggestellt wurde kannst du dich via vagrant ssh auf die Maschine verbinden und das Projekt aufsetzen.

Wähle hierzu, welche Edition der OXID Version 6 du installieren willst.

```auto
cd oxvm_eshop

vagrant up

vagrant ssh

# for the Community Edition

composer create-project oxid-esales/oxideshop-project /var/www/oxideshop dev-b-6.1-ce

# for the Professional Edition

composer create-project oxid-esales/oxideshop-project /var/www/oxideshop dev-b-6.1-pe

# for the Enterprise Edition

composer create-project oxid-esales/oxideshop-project /var/www/oxideshop dev-b-6.1-ee

```

Nach der Installation kannst du neue Pfade für die test\_config eingeben.

In diesem Step empfehle ich die vorgegebenen Pfade beizubehalten und mit Enter weiter zu gehen.

Die Vagrantbox und das Projekt sind nun erfolgreich eingerichtet.

### Installation des OXID Onlineshops

Rufe den Shop nun über die von dir vorgegebene (personal.yml) Url auf und folge den Installationsschritten.

### Erstellung eines Modules für OXID

Um einen Test zu schreiben benötigen wir ein Modul, welches via composer registriert ist.

Das Modul und die Dateien findest du unter [GitHub - CodeCommerce/UnitTestTutorial: Code for unit test tutorial](https://github.com/CodeCommerce/UnitTestTutorial).

Nachdem du die Dateien in dein Projekt kopiert hast (bitte auch die composer.json im Root-Verzeichnis beachten), musst du das Modul via

`composer require codecommerce/unittests –n`

registrieren.

## Unit-Test Testkonfiguration

### test\_config.yml

Im Verzeichnis oxideshop findest du die Testkonfiguration.

Die Datei heißt test\_config.yml und enthalt die Informationen für die Testing Library.

Alle Dateien des Tutorials, unter anderem auch die test\_config.yml, findest du auf Github.

Ändere den Parameter **test\_database\_name** entsprechend deiner Testdatenbank.

### Testeinstellungen in der config.inc.php

Damit die Testdatenbank aufgerufen wird und keine Views benötigt werden, erstellen wir eine weitere config.inc.TEST.php.

Diese Datei enthält Einstellungen für das Testing.

```auto
<?php
error_reporting(E_ALL & ~E_STRICT & ~E_DEPRECATED & ~E_WARNING & ~E_NOTICE);
$this->dbName = 'oxid_test'; // database name
$this->sShopDir = __DIR__ ;
$this->sCompileDir = $this->sShopDir . '/tmp';
$this->iUtfMode = 0;
$this->iDebug = 1;
$this->blSkipViewUsage = true;

```

Eingebunden wird die Datei am Ende der **config.inc.php**.

```auto
if (defined('OXID_PHP_UNIT')) {
include "config.inc.TEST.php";
}

```

Beim Aufruf der Testing Library (runtests) wird OXID\_PHP\_UNIT definiert, somit können wir die Testkonfiguration einbinden.

### Testdatenbank

Dupliziere deine Standard Datenbank ohne View-Tabelle und benenne Sie in den Namen aus der test\_config.yml um.

Folgende Tabellen müssen mit Inhalt gefüllt sein:

- oxcountry
- oxconfig
- oxshops

Die anderen Tabellen benötigen ausschließlich die Struktur.

### Ordnerstruktur

In eurem Modul erstellt Ihr einen Unterordner Unit. Darunter bildet Ihr die normale Struktur eures Modules nach, also Controller oder Model etc.

Beispiel:

`module/Vendor/ModulName/Unit/Controller…`

## Aktivieren der Tests für Modul

Um ein Modul für das Testen zu aktivieren muss in der Datei **test\_config.yml** unter dem Punkt **partial\_module\_paths** das Modul hinzugefügt werden. Solltet Ihr den Code von Github nutzen, so könnt Ihr hier

`partial_module_paths: 'CodeCommerce/UnitTests'`

hinterlegen.

## Erster OXID Unit Test

Zu aller erst testen wir, ob die Testing Library korrekt eingebunden ist.

Dazu erstellen wir eine neue Testklasse unter **modules/CodeCommerce/UnitTests/Unit/Controller/FirstControllerTest.php**

Die Unit-Test Klassen müssen immer von

`\OxidEsales\TestingLibrary\UnitTestCase`

erben.

`class FirstControllerTest extends \OxidEsales\TestingLibrary\UnitTestCase`

In unserem Test prüfen wir, ob **true** gleich **true** ist.

Hierzu verwendet Ihr die folgende Methode.

```auto
/**
* test if test environment works
*/
public function testAssert()
{
$this->assertTrue(true);
}

```

Aufgerufen wird der Test auf der Vagrant-Maschine im Verzeichnis **/var/www/oxideshop** mit dem Befehl

`php vendor/bin/runtests /var/www/oxideshop/source/modules/CodeCommerce/UnitTests/tests/Unit/Controller/FirstControllerTest.php`

**ACHTUNG!** Auch wenn unser Ordner Tests großgeschrieben ist, so muss der Aufruf in der Konsole mit einem kleinen ‚tests’ ausgeführt werden. Das Framework prüft explizit auf Kleinschreibung.

Nachdem Ihr den Tests aufgeführt habt, solltet Ihr dieses Ergebnis erhalten

`OK (1 test, 1 assertion).`

Prima! Wir haben nun erfolgreich die Funktionalität der Testkonfiguration durchgeführt.

### Aufruf des OXID Test runners

Wie bereits oben geschrieben könnt Ihr den Test wie folgt aufrufen

`php vendor/bin/runtests /var/www/oxideshop/source/modules/CodeCommerce/UnitTests/tests/Unit/Controller/FirstControllerTest.php`

Oder Ihr richtet eure IDE entsprechend ein, dass Ihr die OXID Unit-Tests via GUI ausführen könnt. Lest hierzu die Informationen eurer IDE.

## Was ist ein Mock

Ein Mock ist ein Fake-Objekt, oder auch Platzhalter für ein echtes Objekt, welchem wir Funktionen und auch Werte vorgeben können.

Wir können bestimmen, welche Methoden aufgerufen werden, mit welchen Parametern und was diese zurückgeben sollen.

Beispielsweise haben wir in unserer Methode welche wir testen wollen einen Funktionsaufruf.

Dieser Funktionsaufruf wird 1 mal aufgerufen, mit dem Parameter ‚xyz’ und diese Methode wird true zurück geben.

```auto
$mock->expects($this->once())->method('myMethod')->with('xyz')->willReturn(true);

```

Weitere Informationen zum Mock-Objekt findet Ihr unter [Mock-Objekt – Wikipedia](https://de.wikipedia.org/wiki/Mock-Objekt)

## Einfacher Unit-Test

Wir wollen einen Test für unsere Methode articleCheck in der Klasse UnitTestController erstellen.

Dazu benötigen wir die Klasse unter dem Pfad /modules/CodeCommerce/UnitTests/Controller/ mit dem Namen UnitTestController.php

Erstellt darin eine neue Public Function mit dem Namen articleCheck und dem Übergabeparameter $article.

Wir prüfen in der Methode ob der Artikel eine ID besitzt und geben diese zurück **falls** vorhanden, oder geben false zurück.

```auto
<?php

namespace CodeCommerce\UnitTests\Controller;

use OxidEsales\Eshop\Core\Registry;

class UnitTestController
{
/**
* @param $article
* @return bool
*/
public function articleCheck($article)
{
if ($oxid = $article->getId()) {
return $oxid;
}

return false;
}

}

```

Für den Test brauchen wir eine Test Klasse. Diese erstellen wir unter dem Pfad **/modules/CodeCommerce/UnitTests/Tests/Unit/Controller** mit dem Namen **UnitTestControllerTest.php**.

Diese Klasse muss von **OxidEsales\TestingLibrary\UnitTestCase** erben.

Wir erstellen eine neue Test Methode mit dem gleichen Namen wie unsere zu testende Methode und fügen ‚test’ vor den Namen an (testArticleCheck()).

Nun erstellen wir unseren ersten Mock. Dazu holen wir uns das Mock via **getMockBuilder(UnitTestController::class)**.

Wir geben an, dass wir keine Methoden der Originalklasse mocken möchten, deaktivieren den Originalen Konstruktor und lassen uns das Mock-Objekt via getMock() zurück geben.

Das gleiche machen wir mit dem Artikel Objekt. Allerdings mocken wir hier die Funktion getId(), die wir selber mit Daten und Rückgabewerten vorbelegen.

Die Vorbelegung findet wie folgt statt:

```auto
$article->expects($this->once())
->method('getId')
->willReturn($oxid);

```

Wir erwarten, dass die Methode getID einmal auf dem Artikel Objekt aufgerufen wird und diese die von uns gesetzte $oxid zurück gibt.

```auto
<?php

namespace CodeCommerce\UnitTests\Controller;

use OxidEsales\TestingLibrary\UnitTestCase;

class UnitTestControllerTest extends UnitTestCase
{
/**
* @param $oxid
* @param $expected
* @dataProvider dataProviderArticleCheck
*/
public function testArticleCheck($oxid, $expected)
{
$unitTestController = $this->getMockBuilder(UnitTestController::class)
->setMethods(null)
->disableOriginalConstructor()
->getMock();

$article = $this->getMockBuilder(Article::class)
->setMethods(['getId'])
->disableOriginalConstructor()
->getMock();

$article->expects($this->once())
->method('getId')
->willReturn($oxid);

$this->assertEquals($expected, $unitTestController->articleCheck($article));
}

/**
* @return array
*/
public function dataProviderArticleCheck()
{
/** $oxid, $expected */
return [
['123', '123'],
[null, false],
];
}

}

```

## Dataprovider

Damit wir eine Funktion mit mehreren Werten testen können gibt es Dataprovider.

Dataprovider sind Arrays die wir in unsere Testmethode übergeben.

Erstellt dazu eine neue Methode Namens **dataProviderArticleCheck** und gebt ein multidimesionales Array zurück.

Die Reihenfolge der Array Values werden in der zu testenden Methode übergeben.

```auto
…

/** $oxid, $expected */
return [
['123', '123'],
[null, false],
];

public function testArticleCheck($oxid, $expected) …

```

Um den DataProvider nutzen zu können muss dieser über eine Annotation der Testmethode bekannt gemacht werden.

```auto
/**
* @dataProvider dataProviderArticleCheck
*/

```

## Testen von Proteced Functions

Durch das OXID Unit-Test Framework besteht die Möglichkeit Protected Functios testen zu können.

Anstelle des Klassennamens geben wir eine Methode in den MockBuilder.

```auto

$unitTestController = $this->getMockBuilder($this->getProxyClassName(UnitTestController::class))
->setMethods(null)
->disableOriginalConstructor()
->getMock();

```

Im Hintergrund wird eine Proxy-Klasse erstellt, die auf Protected Functions zugreifen kann.

Der Aufruf der Protected Function wird wie eine Public Function durchgeführt.

Solltet Ihr die Protected Function wie im Core mit einem Unterstrich geschrieben haben, ersetzt Ihr den Unterstrich mit ‚UNIT’.

```auto
/**
* @dataProvider dataProviderArticleTitleCheck
* @param $title
* @param $expected
*/
public function testArticleTitleCheck($title, $expected)
{
$unitTestController = $this->getMockBuilder($this->getProxyClassName(UnitTestController::class))
->setMethods(null)
->disableOriginalConstructor()
->getMock();

$article = $this->getMockBuilder(Article::class)
->setMethods(['getTitle'])
->disableOriginalConstructor()
->getMock();

$article->expects($this->once())
->method('getTitle')
->willReturn($title);

$this->assertEquals($expected, $unitTestController->UNITarticleTitleCheck($article));
}

```

Der restliche Test verhält sich wie bei einer Public Function.

Siehe hierzu den Quellcode auf Github.

## Registry Mock

Auch die über die Registry aufgerufenen Methoden wie zum Beispiel Registry::getConfig() können gemocked werden.

Hierzu gibt es eine einfache Möglichkeit.

Wir setzen das normale Config Object mit einem Config-Mock Objekt.

```auto
/**
* @param $configParam
* @param $expected
* @dataProvider dataProviderGetConfigParamForArticleOption
*/
public function testGetConfigParamForArticleOption($configParam, $expected)
{
$unitTestController = $this->getMockBuilder($this->getProxyClassName(UnitTestController::class))
->setMethods(null)
->disableOriginalConstructor()
->getMock();
$registry = $this->getMockBuilder(Registry::class)
->setMethods(null)
->disableOriginalConstructor()
->getMock();
$config = $this->getMockBuilder(Config::class)
->setMethods(['getConfigParam'])
->disableOriginalConstructor()
->getMock();
$registry->set(Config::class, $config);

$config->expects($this->once())
->method('getConfigParam')
->with('testParam')
->willReturn($configParam);

$this->assertEquals($expected, $unitTestController->getConfigParamForArticleOption());
}

```

Natürlich könnt Ihr auch hier einen DataProvider einsetzen um mehrere Testfälle zu prüfen.

## Testen eines Multiplen Aufrufs einer Methode

Es kann vorkommen, das eine Methode mehrfach in einer Methode aufgerufen wird.

Dazu können verschiedene Übergabe- und Rückgabeparameter von Nöten sein.

Um die Übergabeparameter zu separieren gibt es die Funktion **withConsecutive** in der pro Aufruf ein Array mit den Entsprechenden Werten übergeben werden kann.

Die Funktion **willReturnOnConsecutiveCalls** gibt für jeden Aufruf einen Wert zurück.

```auto
    $config->expects($this->exactly($configParamCount))
->method('getConfigParam')
->withConsecutive(['testParam1'], ['testParam2'])
->willReturnOnConsecutiveCalls($configParam1, $configParam2);

```

Beim Testen von Multiplen aufrufen und ggf. If-Abfragen solltet Ihr bei der Nutzung eines DataProviders darauf achten, dass Ihr die korrekte Anzahl von den Aufrufen in die Testmethode übergebt.

```auto
 /**
* @return array
*/
public function dataProviderGetMultipleConfigParams()
{
/**
* $configParam1, $configParam2, $expected, $configParamCount
*/
return [
[true, true, true, 2],
[true, false, false, 2],
[false, true, false, 1],
[false, false, false, 1],
];
}

```

Das komplette Beispiel:

```auto
/**
* @param $configParam1
* @param $configParam2
* @param $expected
* @param $configParamCount
* @dataProvider dataProviderGetMultipleConfigParams
*/
public function testGetMultipleConfigParams($configParam1, $configParam2, $expected, $configParamCount)
{
$unitTestController = $this->getMockBuilder($this->getProxyClassName(UnitTestController::class))
->setMethods(null)
->disableOriginalConstructor()
->getMock();
$registry = $this->getMockBuilder(Registry::class)
->setMethods(null)
->disableOriginalConstructor()
->getMock();
$config = $this->getMockBuilder(Config::class)
->setMethods(['getConfigParam'])
->disableOriginalConstructor()
->getMock();
$registry->set(Config::class, $config);

$config->expects($this->exactly($configParamCount))
->method('getConfigParam')
->withConsecutive(['testParam1'], ['testParam2'])
->willReturnOnConsecutiveCalls($configParam1, $configParam2);

$this->assertEquals($expected, $unitTestController->getMultipleConfigParams());
}

/**
* @return array
*/
public function dataProviderGetMultipleConfigParams()
{
/**
* $configParam1, $configParam2, $expected, $configParamCount
*/
return [
[true, true, true, 2],
[true, false, false, 2],
[false, true, false, 1],
[false, false, false, 1],
];
}

```

[![](https://forum.oxid-esales.com/uploads/default/original/2X/2/24f7ec625f22fe8245867271d77125b61f28295e.jpeg "OXID eSales Unit-Test Tutorial") ](https://www.youtube.com/watch?v=QKqKqF6N14k&t=4s)

---

<div class="post-metadata">

**Author:** ![system](https://forum.oxid-esales.com/user_avatar/forum.oxid-esales.com/system/32/4245_2.png) [@system](https://forum.oxid-esales.com/u/system)\
**Post date:** [July 13, 2026, 8:37pm UTC](https://forum.oxid-esales.com/t/unit-tests-mit-dem-oxid-framework/94723/2 "2026-07-13T20:37:52Z")

</div>


