Ich habe gelesen diese Stelle darüber, wie man private Methoden testet. Ich teste sie normalerweise nicht, weil ich immer dachte, dass es schneller ist, nur öffentliche Methoden zu testen, die von außerhalb des Objekts aufgerufen werden. Testen Sie private Methoden? Sollte ich sie immer testen?
Antworten
Zu viele Anzeigen?Ja, Sie sollten private Methoden testen, wo immer dies möglich ist. Warum? Zur Vermeidung einer unnötigen Zustandsraumexplosion von Testfällen, die letztendlich nur dazu führen, dass dieselben privaten Funktionen wiederholt auf dieselben Eingaben getestet werden. Lassen Sie uns anhand eines Beispiels erklären, warum.
Betrachten Sie das folgende, leicht erfundene Beispiel. Nehmen wir an, wir wollen eine Funktion öffentlich zugänglich machen, die 3 ganze Zahlen annimmt und nur dann true zurückgibt, wenn diese 3 ganzen Zahlen alle Primzahlen sind. Wir könnten sie wie folgt implementieren:
public bool allPrime(int a, int b, int c)
{
return andAll(isPrime(a), isPrime(b), isPrime(c))
}
private bool andAll(bool... boolArray)
{
foreach (bool b in boolArray)
{
if(b == false) return false;
}
return true;
}
private bool isPrime(int x){
//Implementation to go here. Sorry if you were expecting a prime sieve.
}
Wenn wir nun den strikten Ansatz verfolgen würden, dass nur öffentliche Funktionen getestet werden sollten, dürften wir nur testen allPrime
und nicht isPrime
o andAll
.
Als Prüfer sind wir vielleicht an fünf Möglichkeiten für jedes Argument interessiert: < 0
, = 0
, = 1
, prime > 1
, not prime > 1
. Aber um gründlich zu sein, müssten wir auch sehen, wie jede Kombination der Argumente zusammenspielt. Das ist also 5*5*5
= 125 Testfälle, die wir brauchen, um diese Funktion gründlich zu testen, so unsere Intuition.
Wäre es uns hingegen erlaubt, die privaten Funktionen zu testen, könnten wir mit weniger Testfällen genauso viel Fläche abdecken. Wir bräuchten nur 5 Testfälle, um zu testen isPrime
auf die gleiche Ebene wie unsere bisherige Intuition. Und durch die Hypothese des geringen Umfangs Daniel Jackson vorgeschlagen hat, bräuchten wir nur die andAll
Funktion bis zu einer kleinen Länge, z. B. 3 oder 4. Das wären dann höchstens 16 weitere Tests. Insgesamt also 21 Tests. Anstelle von 125. Natürlich würden wir wahrscheinlich einen wenige Tests zu allPrime
aber wir würden uns nicht so verpflichtet fühlen, alle 125 Kombinationen von Eingabeszenarien, die uns wichtig sind, erschöpfend zu behandeln. Nur ein paar glückliche Wege.
Das Beispiel ist sicher etwas konstruiert, aber es war notwendig, um es zu verdeutlichen. Und das Muster lässt sich auf echte Software übertragen. Private Funktionen sind in der Regel die Bausteine der untersten Ebene und werden daher oft miteinander kombiniert, um Logik auf höherer Ebene zu erhalten. Das bedeutet, dass es auf höheren Ebenen aufgrund der verschiedenen Kombinationen mehr Wiederholungen von Elementen der unteren Ebene gibt.
Ich verstehe den Standpunkt, dass private Methoden als Implementierungsdetails betrachtet werden und daher nicht getestet werden müssen. Und ich würde mich an diese Regel halten, wenn wir nur außerhalb des Objekts entwickeln müssten. Aber wir, sind wir eine Art eingeschränkte Entwickler, die nur außerhalb von Objekten entwickeln und nur deren öffentliche Methoden aufrufen? Oder entwickeln wir tatsächlich auch das Objekt? Da wir nicht verpflichtet sind, außerhalb von Objekten zu programmieren, müssen wir wahrscheinlich diese privaten Methoden in neuen öffentlichen Methoden, die wir entwickeln, aufrufen. Wäre es nicht großartig, zu wissen, dass die private Methode allen Widrigkeiten zum Trotz standhält?
Ich weiß, dass einige Leute antworten könnten, dass, wenn wir eine weitere öffentliche Methode für dieses Objekt entwickeln, diese getestet werden sollte und das war's (die private Methode könnte ohne Test weiterleben). Aber das gilt auch für alle öffentlichen Methoden eines Objekts: Bei der Entwicklung einer Webanwendung werden alle öffentlichen Methoden eines Objekts von Controllermethoden aufgerufen und können daher als Implementierungsdetails für Controller betrachtet werden.
Warum also testen wir Objekte in der Einheit? Weil es wirklich schwierig, um nicht zu sagen unmöglich ist, sicher zu sein, dass wir die Methoden des Controllers mit den richtigen Eingaben testen, die alle Verzweigungen des zugrunde liegenden Codes auslösen werden. Mit anderen Worten: Je höher wir im Stack sind, desto schwieriger ist es, das gesamte Verhalten zu testen. Das Gleiche gilt für private Methoden.
Für mich ist die Grenze zwischen privaten und öffentlichen Methoden ein psychologisches Kriterium, wenn es um Tests geht. Kriterien, die für mich wichtiger sind, sind:
- wird die Methode mehr als einmal von verschiedenen Stellen aus aufgerufen?
- Ist die Methode so anspruchsvoll, dass Tests erforderlich sind?