Unit-testing private Methoden: Fassadenmuster

8

Viele Entwickler denken, dass das Testen privater Methoden keine gute Idee ist. Alle Beispiele, die ich gefunden habe, basierten jedoch auf der Idee, dass private Methoden privat sind, da das Aufrufen von ihnen den Status des internen Objekts brechen könnte. Aber das ist nicht nur ein Grund, Methoden zu verstecken.

Betrachten wir das Fassadenmuster. Meine Klassenbenutzer benötigen die zwei öffentlichen Methoden. Sie wären zu groß. In meinem Beispiel müssen sie eine komplexe Struktur aus dem BLOB der Datenbank laden, sie analysieren, einige temporäre COM-Objekte füllen, das Benutzermakro ausführen, um diese Objekte zu validieren und zu modifizieren, und modifizierte Objekte in XML serialisieren. Ziemlich große Funktionalität für den einzelnen Modus :-) Die meisten dieser Aktionen sind für beide öffentlichen Methoden erforderlich. Also habe ich ungefähr 10 private Methoden erstellt und 2 öffentliche Methoden rufen sie auf. Eigentlich sollten meine privaten Methoden nicht unbedingt privat sein; Sie werden den internen Zustand der Instanz nicht brechen. Aber wenn ich nicht versuche, private Methoden zu testen, habe ich die folgenden Probleme:

  1. Sie zu veröffentlichen, bedeutet Komplexität für Benutzer (sie haben die Wahl, die sie nicht brauchen)
  2. Ich kann mir den TDD-Stil für solch eine große öffentliche Methode nicht vorstellen, wenn Sie mehr als 500 Codezeilen schreiben wollen, um etwas zurückzugeben (sogar kein echtes Ergebnis).
  3. Daten für diese Methoden werden aus der Datenbank abgerufen, und das Testen von DB-bezogenen Funktionen ist viel schwieriger.

Wenn ich private Methoden teste:

  1. Ich veröffentliche keine Details, die Benutzer verwirren würden. Öffentliche Schnittstelle enthält 2 Methoden.
  2. Ich kann im TDD-Stil arbeiten (schreibe kleine Methoden Schritt für Schritt).
  3. Ich kann die meisten Funktionen der Klasse mit Testdaten ohne Datenbankverbindung abdecken.

Könnte jemand beschreiben, was mache ich falsch? Welches Design sollte ich verwenden, um die gleichen Boni zu erhalten und keine privaten Methoden zu testen?

UPDATE: Es scheint mir, dass ich alles, was ich konnte, in einem anderen Kurs extrahiert habe. Also, ich kann mir nicht vorstellen, was ich zusätzlich extrahieren könnte. Das Laden aus der Datenbank wird von der ORM-Ebene ausgeführt, der Stream wird analysiert, in XML serialisiert, Makro wird ausgeführt - alles wird von eigenständigen Klassen erledigt. Diese Klasse enthält eine ziemlich komplexe Datenstruktur, Routinen zum Suchen und Konvertieren und ruft alle erwähnten Dienstprogramme auf. Also glaube ich nicht, dass etwas anderes extrahiert werden könnte; Andernfalls würde seine Verantwortung (Wissen über die Datenstruktur) zwischen den Klassen aufgeteilt.

Also, die beste Methode, um zu lösen, sehe ich jetzt in der Aufteilung in zwei Objekte (Fassade selbst und reales Objekt, mit privaten Methoden werden öffentlich) und bewegliches Objekt zu irgendwem, wo niemand versuchen würde es zu finden. In meinem Fall (Delphi) wäre es eine eigenständige Einheit, in anderen Sprachen könnte es ein separater Namensraum sein. Andere ähnliche Option ist 2 Schnittstellen, danke für die Idee.

    
Abelevich 08.01.2009, 20:13
quelle

7 Antworten

17

Ich denke, dass Sie zu viele Verantwortlichkeiten (Implementierungen) in die Fassade setzen. Ich würde dies normalerweise als Front-End für tatsächliche Implementierungen in anderen Klassen betrachten.

Daher sind die privaten Methoden in Ihrer Fassade wahrscheinlich öffentliche Methoden in einer oder mehreren anderen Klassen. Dann kannst du sie dort testen.

    
krosenvold 08.01.2009, 20:17
quelle
4
  

Könnte jemand beschreiben, was ich bin?   falsch gemacht?

Vielleicht nichts?

Wenn ich eine Methode testen möchte, stelle ich sie als Standard (Paket) ein und teste sie.

Sie haben bereits eine andere gute Lösung erwähnt: Erstellen Sie eine Schnittstelle mit Ihren beiden Methoden. Ihre Clients greifen auf diese beiden Methoden zu und die Sichtbarkeit der anderen Methoden spielt keine Rolle.

    
Jeffrey Fredrick 08.01.2009 20:41
quelle
3

Private Methoden werden verwendet, um ein Verhalten einzukapseln, das außerhalb der Klasse, die Sie testen möchten, keine Bedeutung hat. Sie sollten niemals private Methoden testen müssen, da nur die öffentlichen oder geschützten Methoden derselben Klasse jemals private Methoden aufrufen.

Es kann einfach sein, dass Ihre Klasse sehr komplex ist und es viel Mühe kosten wird, sie zu testen. Allerdings würde ich vorschlagen, dass Sie nach Abstraktionen suchen, die Sie in ihre eigenen Klassen ausbrechen können. Diese Klassen haben einen geringeren Umfang an Elementen und Komplexität zum Testen.

    
Aaron Rustad 08.01.2009 20:23
quelle
2

Vielleicht, wenn Sie sich Zeit nehmen und die Clean Code Tech spricht von Miško. Er ist sehr einsichtig, wie Code geschrieben werden sollte, um getestet zu werden.

    
Drejc 08.01.2009 20:48
quelle
2

Dies ist ein wenig kontroverses Thema ... Die meisten TDDer sind der Meinung, dass das Refactoring Ihrer Methoden für einfachere Unit-Tests Ihr Design tatsächlich verbessert. Ich denke, dass dies oft der Fall ist, aber der spezifische Fall von privaten Methoden für öffentliche APIs ist definitiv eine Ausnahme. Also, ja, Sie sollten private Methode testen, und nein, Sie sollten es nicht öffentlich machen.

Wenn Sie in Java arbeiten, ist hier eine von mir geschriebene Hilfsmethode, mit der Sie statische private Methoden in einer Klasse testen können:

%Vor%

Dies könnte wahrscheinlich auch für nicht-statische Methoden umgeschrieben werden, aber diese lästigen privaten Methoden sind normalerweise privat, also brauchte ich das nie. :)

    
Domchi 08.01.2009 21:57
quelle
2

Angenommen, Sie haben 8 private und 2 öffentliche Methoden. Wenn Sie eine private Methode unabhängig ausführen können, d. H. ohne eine der anderen Methoden aufzurufen, und ohne staatsschädigende Nebenwirkungen , dann ist das Unit-Testen genau dieser Methode sinnvoll. Aber dann braucht die Methode nicht privat zu sein!

in C # würde ich solche Methoden anstelle von privat schützen und sie als public in einer Unterklasse zum Testen freigeben

In Anbetracht Ihres Szenarios könnte es sinnvoller sein, wenn die testbaren Methoden öffentlich sind und der Benutzer eine echte Fassade mit nur den zwei öffentlichen Methoden haben soll, die er für seine Schnittstelle benötigt.

    
Steven A. Lowe 09.01.2009 08:51
quelle
2

Ich bin nicht vertraut mit Ihren Anforderungen & amp; Design, aber es scheint, dass Ihr Design eher prozedural als objektorientiert ist. Sie haben 2 öffentliche Methoden und viele private Methoden. Wenn Sie Ihre Klasse in Objekte zerlegen, in denen jedes Objekt seine Rolle hat, wäre es einfacher, jede der "kleinen" Klassen zu testen. Zusätzlich können Sie die Zugriffsebene "helper" Objekte auf Paket setzen (der Standard in Java, ich weiß, dass es in C # eine ähnliche Zugriffsebene gibt), so dass Sie sie nicht in der API verfügbar machen, aber Sie können sie unabhängig testen (wie sie sind Einheiten).

    
LiorH 08.01.2009 20:23
quelle

Tags und Links