508 Stimmen

Wie testet man private Methoden in der Einheit?

Ich baue eine Klassenbibliothek, die einige öffentliche und private Methoden haben wird. Ich möchte in der Lage sein, die privaten Methoden zu testen (vor allem während der Entwicklung, aber auch es könnte für zukünftige Refactoring nützlich sein).

Wie geht man dabei richtig vor?

3 Stimmen

Vielleicht übersehe ich etwas, oder vielleicht ist diese Frage einfach nur, nun ja... pre-historic in Bezug auf Internet Jahre, aber Unit-Tests von privaten Methoden ist jetzt sowohl einfach und unkompliziert, mit Visual Studio produziert die notwendigen Accessor-Klassen, wenn nötig und Pre-Füllung der Tests Logik mit Schnipseln verdammt nah an das, was man für einfache funktionale Tests wünschen kann. Siehe z.B.. msdn.microsoft.com/de-us/library/ms184807%28VS.90%29.aspx

5 Stimmen

Dies scheint fast ein Duplikat zu sein von stackoverflow.com/questions/34571/ .

0 Stimmen

Der Fragesteller verwendet möglicherweise nicht Visual Studio

361voto

Jeroen Heijmans Punkte 4488

Wenn Sie eine private Methode einem Unit-Test unterziehen wollen, kann etwas falsch sein. Unit-Tests sind (im Allgemeinen) dazu gedacht, die Schnittstelle einer Klasse zu testen, also ihre öffentlichen (und geschützten) Methoden. Sie können natürlich eine Lösung für dieses Problem "hacken" (und sei es nur, indem Sie die Methoden öffentlich machen), aber Sie sollten sich auch Gedanken machen:

  1. Wenn die Methode, die Sie testen möchten, es wirklich wert ist, getestet zu werden, kann es sich lohnen, sie in eine eigene Klasse zu verschieben.
  2. Fügen Sie den öffentlichen Methoden, die die private Methode aufrufen, weitere Tests hinzu, um die Funktionalität der privaten Methode zu testen. (Wie die Kommentatoren anmerkten, sollten Sie dies nur tun, wenn die Funktionalität dieser privaten Methoden wirklich ein Teil der öffentlichen Schnittstelle ist. Wenn sie tatsächlich Funktionen ausführen, die dem Benutzer (d.h. dem Einheitstest) verborgen bleiben, ist dies wahrscheinlich schlecht).

43 Stimmen

Bei Option 2 müssen die Unit-Tests Kenntnisse über die zugrunde liegende Implementierung der Funktion haben. Das gefällt mir nicht. Ich denke im Allgemeinen, dass Unit-Tests die Funktion testen sollten, ohne etwas über die Implementierung anzunehmen.

17 Stimmen

Der Nachteil beim Testen der Implementierung ist, dass die Tests anfällig sind, wenn Sie Änderungen an der Implementierung vornehmen. Und das ist nicht wünschenswert, da das Refactoring genauso wichtig ist wie das Schreiben der Tests in TDD.

32 Stimmen

Nun, die Tests sollen zu brechen, wenn Sie die Implementierung ändern. TDD würde bedeuten, dass man zuerst die Tests ändert.

127voto

TcKs Punkte 24671

Wenn Sie .net verwenden, sollten Sie die InternalsVisibleToAttribute .

89 Stimmen

Igitt. Dies wird in Ihre freigegebenen Assemblies kompiliert.

16 Stimmen

@Jay - könnte man nicht verwenden #if DEBUG um den InternalsVisibleTo Attribut, damit es nicht für den Freigabecode gilt?

21 Stimmen

@Mike, das könnten Sie, aber dann können Sie Unit-Tests nur mit Debug-Code durchführen, nicht mit Release-Code. Da der Release-Code optimiert ist, kann es sein, dass Sie ein anderes Verhalten und andere Zeitabläufe feststellen. Bei Multithreading-Code bedeutet dies, dass Ihre Unit-Tests Race Conditions nicht angemessen erkennen. Viel besser ist es, Reflection über @AmazedSaint's Vorschlag unten zu verwenden oder das eingebaute PrivateObject/PrivateType zu benutzen. Dies ermöglicht es Ihnen, PrivateObjects in Release-Builds zu sehen, vorausgesetzt, Ihr Test-Harness läuft mit vollem Vertrauen (was MSTest, das lokal läuft, tut)

122voto

Seven Punkte 4233

Es ist vielleicht nicht sinnvoll, private Methoden zu testen. Manchmal rufe ich aber auch gerne private Methoden von Testmethoden aus auf. Meistens, um Code-Duplizierung für die Testdatengenerierung zu vermeiden...

Microsoft bietet hierfür zwei Mechanismen an:

Accessors

  • Gehen Sie zum Quellcode der Klassendefinition
  • Klicken Sie mit der rechten Maustaste auf den Namen der Klasse
  • Wählen Sie "Privaten Accessor erstellen".
  • Wählen Sie das Projekt, in dem der Accessor erstellt werden soll => Sie erhalten eine neue Klasse mit dem Namen foo_accessor. Diese Klasse wird beim Kompilieren dynamisch erzeugt und stellt alle Mitglieder öffentlich zur Verfügung.

Allerdings ist der Mechanismus manchmal etwas schwerfällig, wenn es um Änderungen an der Schnittstelle der ursprünglichen Klasse geht. Daher vermeide ich es meistens, dies zu verwenden.

PrivateObject-Klasse Die andere Möglichkeit ist die Verwendung von Microsoft.VisualStudio.TestTools.UnitTesting.PrivateObject

// Wrap an already existing instance
PrivateObject accessor = new PrivateObject( objectInstanceToBeWrapped );

// Retrieve a private field
MyReturnType accessiblePrivateField = (MyReturnType) accessor.GetField( "privateFieldName" );

// Call a private method
accessor.Invoke( "PrivateMethodName", new Object[] {/* ... */} );

3 Stimmen

Wie ruft man private statische Methoden auf?

20 Stimmen

Private Accessoren sind veraltet in Visual Studio 2012 .

3 Stimmen

Die Accessor-Methode zum Testen privater Methoden wird ab VS 2011 veraltet sein. blogs.msdn.com/b/visualstudioalm/archive/2012/03/08/

90voto

Darrell Plank Punkte 1054

Ich bin nicht einverstanden mit der Philosophie, dass man nur an der Prüfung der externen Schnittstelle interessiert sein sollte. Das ist ein bisschen so, als würde man sagen, dass eine Autowerkstatt nur testen sollte, ob sich die Räder drehen. Ja, letztendlich bin ich an dem externen Verhalten interessiert, aber ich möchte, dass meine eigenen, privaten, internen Tests etwas spezifischer und zielgerichteter sind. Ja, wenn ich ein Refactoring durchführe, muss ich vielleicht einige der Tests ändern, aber wenn es sich nicht um ein massives Refactoring handelt, muss ich nur einige wenige ändern, und die Tatsache, dass die anderen (unveränderten) internen Tests immer noch funktionieren, ist ein guter Indikator dafür, dass das Refactoring erfolgreich war.

Man kann versuchen, alle internen Fälle nur über die öffentliche Schnittstelle abzudecken, und theoretisch ist es möglich, jede interne Methode (oder zumindest jede, die von Bedeutung ist) vollständig über die öffentliche Schnittstelle zu testen, aber dazu muss man sich möglicherweise auf den Kopf stellen, und die Verbindung zwischen den Testfällen, die über die öffentliche Schnittstelle ausgeführt werden, und dem internen Teil der Lösung, den sie testen sollen, kann schwierig oder unmöglich zu erkennen sein. Gezielte Einzeltests, die garantieren, dass die interne Maschinerie ordnungsgemäß funktioniert, sind die geringfügigen Teständerungen, die mit dem Refactoring einhergehen, auf jeden Fall wert - das ist zumindest meine Erfahrung. Wenn Sie bei jedem Refactoring große Änderungen an Ihren Tests vornehmen müssen, dann macht das vielleicht keinen Sinn, aber in diesem Fall sollten Sie vielleicht Ihr Design komplett überdenken. Ein gutes Design sollte so flexibel sein, dass es die meisten Änderungen ohne große Umgestaltungen zulässt.

21 Stimmen

Ich fürchte, ich bin immer noch anderer Meinung als Sie. Wenn man jede Komponente wie eine Blackbox behandelt, kann man Module problemlos austauschen. Wenn Sie eine FooService das hat zu tun mit X sollten Sie nur darauf achten, dass es tatsächlich funktioniert. X auf Anfrage. Wie sollte es keine Rolle spielen. Wenn es Probleme in der Klasse gibt, die durch die Schnittstelle nicht erkennbar sind (unwahrscheinlich), ist es immer noch eine gültige FooService . Wenn es ein Problem ist, das es über die Schnittstelle sichtbar ist, sollte ein Test auf öffentliche Mitglieder dies erkennen. Der springende Punkt ist, dass das Rad als Rad verwendet werden kann, solange es sich richtig dreht.

6 Stimmen

Ein allgemeiner Ansatz ist, dass, wenn Ihre interne Logik so kompliziert ist, dass sie Unit-Tests erfordert, sie vielleicht in eine Art Hilfsklasse mit einer öffentlichen Schnittstelle extrahiert werden sollte, die Unit-Tests unterzogen werden kann. Dann kann Ihre "übergeordnete" Klasse einfach diese Hilfsklasse verwenden, und alle können entsprechend unitgetestet werden.

12 Stimmen

@Basic: Völlig falsche Logik in dieser Antwort. Der klassische Fall, in dem man private Methoden braucht, ist, wenn man Code braucht, der von öffentlichen Methoden wiederverwendet werden kann. Sie legen diesen Code in eine PrivMethode. Diese Methode sollte nicht öffentlich zugänglich sein, sondern muss getestet werden, um sicherzustellen, dass öffentliche Methoden, die sich auf PrivMethod verlassen, sich auch wirklich darauf verlassen können.

52voto

Jason Jackson Punkte 16792

In den seltenen Fällen, in denen ich private Funktionen testen wollte, habe ich sie in der Regel so geändert, dass sie stattdessen geschützt sind, und dann eine Unterklasse mit einer öffentlichen Wrapper-Funktion geschrieben.

Die Klasse:

...

protected void APrivateFunction()
{
    ...
}

...

Unterklasse zum Testen:

...

[Test]
public void TestAPrivateFunction()
{
    APrivateFunction();
    //or whatever testing code you want here
}

...

2 Stimmen

Sie können diese untergeordnete Klasse sogar in Ihre Unit-Test-Datei aufnehmen, anstatt die eigentliche Klasse zu überladen. +1 für Gerissenheit.

0 Stimmen

Ich lege immer alle testbezogenen Code in der Einheit Tests Projekt, wenn möglich. Dies war nur Pseudocode.

3 Stimmen

Diese Funktion ist nicht privat, es ist geschützt, das Nettoergebnis ... Sie haben Ihren Code weniger sicher / ausgesetzt, um Kind Typen private Funktionalität

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X