Ich fand die Diskussion über Testen Sie private Methoden informativ.
Ich habe beschlossen, dass ich in einigen Klassen geschützte Methoden haben möchte, aber sie testen. Einige dieser Methoden sind statisch und kurz. Da die meisten öffentlichen Methoden sie verwenden, kann ich die Tests wahrscheinlich später sicher entfernen. Aber um mit einem TDD-Ansatz zu beginnen und das Debuggen zu vermeiden, möchte ich sie wirklich testen.
Ich dachte an Folgendes:
- Das in einer Antwort empfohlene Methodenobjekt scheint dafür übertrieben zu sein.
- Beginnen Sie mit öffentlichen Methoden. Wenn die Codeabdeckung durch Tests höherer Ebene gegeben ist, schalten Sie sie geschützt aus und entfernen Sie die Tests.
- Erben Sie eine Klasse mit einer testbaren Schnittstelle, die geschützte Methoden öffentlich macht
Welches ist die beste Vorgehensweise? Gibt es noch etwas?
Es scheint, dass JUnit geschützte Methoden automatisch ändert, um öffentlich zu sein, aber ich habe es mir nicht genauer angesehen. PHP erlaubt dies nicht durch Reflexion .
php
unit-testing
phpunit
GrGr
quelle
quelle
Antworten:
Wenn Sie PHP5 (> = 5.3.2) mit PHPUnit verwenden, können Sie Ihre privaten und geschützten Methoden testen, indem Sie Reflection verwenden, um sie vor dem Ausführen Ihrer Tests als öffentlich festzulegen:
quelle
protected
Methode auch Teil der öffentlichen API, da jede Klasse von Drittanbietern sie erweitern und ohne Magie verwenden kann. Ich denke also, dass nurprivate
Methoden in die Kategorie der Methoden fallen, die nicht direkt getestet werden sollen.protected
undpublic
sollte direkt getestet werden.Sie scheinen es bereits zu wissen, aber ich werde es trotzdem wiederholen. Es ist ein schlechtes Zeichen, wenn Sie geschützte Methoden testen müssen. Das Ziel eines Komponententests besteht darin, die Schnittstelle einer Klasse zu testen, und geschützte Methoden sind Implementierungsdetails. Es gibt jedoch Fälle, in denen dies sinnvoll ist. Wenn Sie die Vererbung verwenden, sehen Sie eine Oberklasse als Schnittstelle für die Unterklasse. Hier müssten Sie also die geschützte Methode testen (aber niemals eine private ). Die Lösung hierfür besteht darin, zu Testzwecken eine Unterklasse zu erstellen und damit die Methoden verfügbar zu machen. Z.B.:
Beachten Sie, dass Sie die Vererbung jederzeit durch Komposition ersetzen können. Beim Testen von Code ist es normalerweise viel einfacher, mit Code umzugehen, der dieses Muster verwendet. Daher sollten Sie diese Option in Betracht ziehen.
quelle
Teastburn hat den richtigen Ansatz. Noch einfacher ist es, die Methode direkt aufzurufen und die Antwort zurückzugeben:
Sie können dies einfach in Ihren Tests aufrufen, indem Sie:
quelle
Ich möchte eine kleine Variation von getMethod () vorschlagen, die in uckelmans Antwort definiert ist .
Diese Version ändert getMethod (), indem fest codierte Werte entfernt und die Verwendung ein wenig vereinfacht werden. Ich empfehle, es Ihrer PHPUnitUtil-Klasse wie im folgenden Beispiel oder Ihrer PHPUnit_Framework_TestCase-Erweiterungsklasse (oder vermutlich global Ihrer PHPUnitUtil-Datei) hinzuzufügen.
Da MyClass sowieso instanziiert wird und ReflectionClass eine Zeichenfolge oder ein Objekt aufnehmen kann ...
Ich habe auch eine Alias-Funktion getProtectedMethod () erstellt, um explizit anzugeben, was erwartet wird, aber das liegt bei Ihnen.
Prost!
quelle
Ich denke, troelskn ist nah dran. Ich würde dies stattdessen tun:
Implementieren Sie dann Folgendes:
Anschließend führen Sie Ihre Tests gegen TestClassToTest aus.
Es sollte möglich sein, solche Erweiterungsklassen automatisch zu generieren, indem der Code analysiert wird. Es würde mich nicht wundern, wenn PHPUnit bereits einen solchen Mechanismus anbietet (obwohl ich nicht überprüft habe).
quelle
Ich werde hier meinen Hut in den Ring werfen:
Ich habe den __call-Hack mit gemischtem Erfolg verwendet. Die Alternative, die ich mir ausgedacht habe, war die Verwendung des Besuchermusters:
1: Generieren Sie eine stdClass oder eine benutzerdefinierte Klasse (um den Typ zu erzwingen).
2: Primen Sie das mit der erforderlichen Methode und den erforderlichen Argumenten
3: Stellen Sie sicher, dass Ihr SUT über eine acceptVisitor-Methode verfügt, die die Methode mit den in der besuchenden Klasse angegebenen Argumenten ausführt
4: Injizieren Sie es in die Klasse, die Sie testen möchten
5: SUT injiziert das Ergebnis der Operation in den Besucher
6: Wenden Sie Ihre Testbedingungen auf das Ergebnisattribut des Besuchers an
quelle
Sie können __call () generisch verwenden, um auf geschützte Methoden zuzugreifen. Um diese Klasse testen zu können
Sie erstellen eine Unterklasse in ExampleTest.php:
Beachten Sie, dass die __call () -Methode in keiner Weise auf die Klasse verweist, sodass Sie das Obige für jede Klasse mit geschützten Methoden kopieren können, die Sie testen möchten, und einfach die Klassendeklaration ändern können. Möglicherweise können Sie diese Funktion in eine gemeinsame Basisklasse einfügen, aber ich habe sie nicht ausprobiert.
Jetzt unterscheidet sich der Testfall selbst nur darin, wo Sie das zu testende Objekt erstellen und in ExampleExposed gegen Example austauschen.
Ich glaube, mit PHP 5.3 können Sie Reflection verwenden, um die Zugänglichkeit von Methoden direkt zu ändern, aber ich gehe davon aus, dass Sie dies für jede Methode einzeln tun müssen.
quelle
call_user_method_array()
Funktion ist ab PHP 4.1.0 veraltet ...call_user_func_array(array($this, $method), $args)
stattdessen verwenden. Beachten Sie, dass Sie, wenn Sie PHP 5.3.2+ verwenden, Reflection verwenden können, um Zugriff auf geschützte / private Methoden und Attribute zu erhaltenAccessible
Paket geschrieben, das Reflektion verwendet, um Tests den Zugriff auf private / geschützte Eigenschaften und Methoden von Klassen und Objekten zu ermöglichen.__call()
nur aufgerufen, wenn der Aufrufer keinen Zugriff auf die Methode hat. Da die Klasse und ihre Unterklassen Zugriff auf die geschützten Methoden haben, werden Aufrufe an sie nicht durchgeführt__call()
. Können Sie Ihren Code, der in 5.2.7 nicht funktioniert, in einer neuen Frage veröffentlichen? Ich habe das Obige in 5.2 verwendet und bin erst mit 5.3.2 zur Reflexion übergegangen.Ich schlage vor, die Problemumgehung für die Problemumgehung / Idee von "Henrik Paul" zu befolgen :)
Sie kennen Namen privater Methoden Ihrer Klasse. Zum Beispiel sind sie wie _add (), _edit (), _delete () usw.
Wenn Sie es daher unter dem Aspekt des Unit-Tests testen möchten, rufen Sie einfach private Methoden auf, indem Sie ein allgemeines Wort (z. B. _addPhpunit) voranstellen und / oder anhängen, damit beim Aufrufen der Methode __call () die Methode aufgerufen wird (da die Methode _addPhpunit () dies nicht tut exist) der Eigentümerklasse, geben Sie einfach den erforderlichen Code in die __call () -Methode ein, um vorangestellte / angehängte Wörter (Phpunit) zu entfernen und dann die abgeleitete private Methode von dort aufzurufen. Dies ist eine weitere gute Anwendung magischer Methoden.
Versuch es.
quelle