Magento: Testen von Configuration Backend Models

Eine professionell entwickelte Magento-Extension will natürlich mit Unit Tests entwickelt werden und der modulare Aufbau sollte dies einfach machenIch nutze dazu die PHPUnit Erweiterung von EcomDev, die sich um das Ausführen der Tests, Instantiierung der Magento-Applikation, Test-Daten und mehr kümmert. In der Praxis tauchen aber häufig unerwartete Fallstricke auf, einen davon will ich hier kurz beschreiben:

Configuration Backend Models sind fürs Speichern und Laden von Werten in der Systemkonfiguration zuständig und können beispielsweise Anpassungen in beforeSave() und afterLoad() oder Validierungen vornehmen.

Mein erster Ansatz, diese Methoden zu testen, war das setzen über die Magento-Applikation:

// Hilfs-Methoden im Test Case:
	private function setConfig($value)
	{
		Mage::getConfig()->saveConfig(
			self::XML_PATH, $value)->cleanCache();
		// sicher stellen dass die neue Konfiguration gespeichert und wieder geladen ist:
		Mage::reset();
		Mage::init();
	}
	private function getConfig()
	{
		return Mage::getStoreConfig(
			self::XML_PATH);
	}

Dabei stellte sich heraus, dass mein Backend Model gar nicht benutzt wurde und natürlich ist der Fehler immer da wo man ihn zuletzt sucht: In Magentos Methoden zum setzen und abfragen von Konfigurationswerten wird direkt auf das Resource Model zugegriffen, das Backend Model kommt nur im User Interface zum Tragen.

Die Lösung ist also, das Backend Model direkt zu instantiieren und zu testen, dabei ist folgendes zu beachten:

Zunächst muss der bestehende Datensatz geladen werden, ansonsten gibt es beim Speichern Konflikte mit dem UNIQUE Index. Ich mache das über den Konfigurations-Pfad, bei mehreren Werten (z.B. Store-spezifische Konfiguration) ist die Abfrage mit load() leider nicht mehr eindeutig und müsste entsprechend zusammengebaut werden. So lange es für den Test nicht relevant ist, mit welchem konkreten Wert gearbeitet wird, kann es allerdings trotzdem so gemacht werden.

// Aufsetzen des Test Case:
	public function setUp()
	{
		parent::setUp();
		$this->model = Mage::getModel(self::MODEL)
			->load(self::XML_PATH, 'path');
	}

Die Hilf-Methoden von oben konnte ich dann refaktorisieren:

// Hilfsmethoden im Test Case:
	private function setConfig($value)
	{
		$this->model->setValue($value);
		$this->model->save();
	}
	private function getConfig()
	{
		return $this->model->getValue();
	}

Das ist so einfach dass nun eigentlich keine eigenen Methoden dafür mehr nötig wären, aber ich hatte sie nun schonmal angelegt. Weiterhin sind sie auf das Testen des Speicherns ausgerichtet (es ging mir konkret um beforeSave()), es sollte aber ein leichtes sein, bei Bedarf getConfig() um erneutes Laden zu erweitern.

Ein einfacher Test könnte nun so aussehen:

// Test
	/**
	 * @test
	 */
	public function testConvertKbOnSave()
	{
		$input = '1K';
		$expected = '1024';

		$this->setConfig($input);
		$this->assertEquals($expected, $this->getConfig(), 'configuration should be changed');
		$this->assertFalse($this->model->hasDataChanges(), 'configuration should be saved');
	}

Viel Erfolg!