Scheinabhängigkeiten in Magento 2-Integrationstests

8

Angenommen, das folgende Szenario:

  • Ich habe eine Klasse, die einen externen Dienst anruft
  • Die Klasse implementiert eine Schnittstelle und ist als bevorzugte Implementierung für diese Schnittstelle in definiert di.xml
  • Ein Block empfängt diese Schnittstelle als Konstruktorparameter
  • Ich möchte eine Magento-Anfrage in einem Integrationstest testen, der diesen Block verwendet

Ich möchte den externen Dienst nicht anrufen, deshalb möchte ich mich über diese Klasse lustig machen und mich fragen, wie das am besten geht.

Ich weiß, dass Sie DI-Einstellungen im laufenden Betrieb mit definieren können

$objectManager->configure(
    ['preferences' => [TheInterface::class => MockClass::class]]
);

Dafür muss jedoch selbst eine Mock-Klasse definiert MockClasswerden. Ich kann kein PHPUnit-Mock-Objekt verwenden.

Dies funktioniert in Ordnung, wenn die injizierte Klasse eine Factory ist, da ich eine Mock-Factory erstellen kann, die das eigentliche Mock-Objekt erstellt.

Aber ist das der einzige Weg oder fehlt mir etwas?

Aktualisieren:

Die vorgeschlagene Methode

$objectManager->addSharedInstance($mock, TheInterface::class);

sah zuerst gut aus, funktionierte aber nur, solange keine Präferenzen definiert waren. Diese haben Vorrang vor gemeinsam genutzten Instanzen.

Ich habe versucht, die Einstellung dynamisch zu entfernen:

$this->objectManager->configure(
    ['preferences' => [TheInterface::class => null]]
);

Leider ruft Magento ltrim($to, '\\')das Argument auf, das es in eine leere Zeichenfolge konvertiert. Das führt zu:

ReflectionException: Klasse existiert nicht

Fabian Schmengler
quelle

Antworten:

5

Sie können hierfür \ Magento \ TestFramework \ ObjectManager :: addSharedInstance verwenden.

Beispiel:

$objectManager->addSharedInstance($mock, TheInterface::class);
KAndy
quelle
Funktioniert gut, wenn noch keine Voreinstellung festgelegt di.xmlist, die Voreinstellung jedoch Vorrang vor der gemeinsam genutzten Instanz zu haben scheint.
Fabian Schmengler
2
In diesem Fall müssen Sie eine gemeinsam genutzte Schnittstelle für die bevorzugte Klasse hinzufügen. zum Beispiel. Wenn wir <Vorzug für = "Psr \ Log \ LoggerInterface" type = "Magento \ Framework \ Logger \ Monolog" /> haben, sollten Sie eine gemeinsam genutzte Instanz als $ objectManager-> addSharedInstance ($ mock, "Magento \ Framework \ Logger \" hinzufügen) Monolog");
KAndy
Schön, das hat funktioniert!
Fabian Schmengler
Bitte beachten Sie, dass Sie, wenn Sie einen virtuellen Typ verspotten möchten, den Namen des virtuellen Typs verwenden müssen, nicht den Klassennamen : $this->objectManager->addSharedInstance($mockedLogger, 'CustomLogger');. Das zu wissen hätte mir eine Stunde gespart :-P
Giel Berkers