Wie eine Schnittstelle zu erstellen, hält einige Methoden für interne Tests in C#?
Betrachten Sie die folgende Klasse
public class Entity {
public void Foo() { ... }
internal void Bar() { ... }
}
Wie Sie sehen, hat es eine public
Methode und ein internal
Methode. Nun, ich möchte eine Benutzeroberfläche erstellen, die mir erlauben wird, zu verspotten, die diese Klasse in den tests (sowohl in dieser Versammlung und in anderen nicht). Ich umschreiben, mein code wie folgt:
public interface IEntity {
void Foo();
}
internal class Entity : IEntity {
public void Foo() { ... }
public void Bar() { ... }
}
Jedoch, dies schafft ein weiteres Problem. Bei der Verwendung der Klasse in einer anderen Methode in die Versammlung, ich kann nicht mitgehen Bar
mehr:
public class OtherClass {
public void SomeMethod(IEntity entity) {
entity.Bar(); //error!
}
}
Den code umschreiben, wie dieses:
public class OtherClass {
public void SomeMethod(IEntity entity) {
(entity as Entity).Bar(); //error in test!
}
}
auslösen wird, ein Fehler in der unit-test auslöst SomeMethod
. Wie muss ich meinen code umschreiben, so dass ich weiterhin verwenden können internal
Methoden in der gleichen assembly und doch enthüllen nur öffentliche Mitglieder zu anderen Baugruppen?
Update: Klasse OtherClass
ist eine utility-Klasse, die Bedürfnisse zu bedienen, die auf Interna der Entity
Klasse, die sind nicht ausgesetzt, um die Benutzer direkt. Jedoch, diese Klasse selbst ist für die Benutzer verfügbar gemacht, damit Sie indirekt Zugriff auf Interna der Entity
. Dies ist gewünscht, da SomeMethod
führen erforderliche Prüfungen durch, um sicherzustellen, dass die Benutzer sich nicht Schraube bis der interne Zustand eines Entity
Objekt.
- Warum gehst du nicht einfach machen, die virtuelle Methoden erstellen, anstatt eine Schnittstelle?
- Weil ich will auch eine klare Schnittstelle für die Benutzer, nicht gemischt mit privaten/internen Mitgliedern und Umsetzung. Und auch, weil ich möchte in der Lage sein, um eine unterschiedliche Umsetzung der in der Zukunft ohne Umbau alle abhängigen Projekte. Jedoch in Anbetracht all der Schwierigkeiten, welche die Schnittstellen erstellen, wenn der Umgang mit internen Mitgliedern, ich könnte wählen Sie diese option, trotz der oben genannten Vorteile.
Du musst angemeldet sein, um einen Kommentar abzugeben.
Bearbeitet:
Erweitern Sie Ihre
IEntity
- interface mit einer internenITestEntity
Schnittstelle für die Prüfung:IEntity
setzenFoo
undITestEntity
hätte setzenBar
, die erforderlich wäre, um pass internenITestEntity
öffentlichenSomeMethod
. Dies führt zu inkonsistenten Zugänglichkeit Fehler.IEntity
Sie werfen kann, umITestEntity
(Sie sollten mockITestEntity
), und dessen Methoden verwenden. Ich gebe zu, es bekommt weniger elegant, da.Mock<IEntity>
in dieSomeMethod
werden, da Sie nicht schreiben unit-test für Sie. Stattdessen werden Sie nur übergebenEntity
. Ich denke, das kann eigentlich problem lösen. Wir trafen testen, ob dies funktioniert und wenn ja, werde ich markieren Sie Ihre Antwort als akzeptiert.Stellen Sie die Schnittstelle zu internen und dann explizit implementieren.
So, jetzt public class
Thing
hat nur eine einzige öffentliche MethodeFoo
. Code außerhalb der assembly nicht nennenBar
entweder direkt oder über eine Konvertierung in die Schnittstelle, daBar
undITest
sind sowohl interne als.Ich den Hinweis, dass ein Basisklasse muss mindestens so sichtbar wie seine abgeleitete Klasse. Nicht so Schnittstellen. Nur wenige Menschen wissen, dass dies legal ist:
Einer Klasse kann eine Schnittstelle implementieren, die nur er sehen kann! Das ist ein bisschen eine seltsame Sache zu tun, aber es gibt einige Situationen, wo es Sinn macht.
Thing
Klasse außerhalb der assembly. Sie kann schreiben, Klassen mitThing
und wird wahrscheinlich wollen, um unit-test auch bei Ihnen.Bar
zugänglich ist, außerhalb der assembly, oder es ist es nicht.Foo
als Sie sich gar nicht kennenBar
Existenz.Ich nehme an, Sie wollen zum Aufruf der internen Methode nur in Ihre unit-tests richtig? Denn sonst, so dass die Methode zu anderen Baugruppen erfordern würde, um zu ersetzen Sie die internen mit der öffentlichkeit führen.
Für unit-Tests im Allgemeinen, es ist immer ein gutes Muster, wenn Sie NICHT testen, privaten oder internen Methoden. Ein Unit-test sollte eigentlich nur testen Sie die öffentliche Schnittstelle, und jeder business-Klasse sollte public Methoden, die das tun, was intern...
So testen Sie Ihre internen Methoden, die Sie haben würde, um zu testen, die öffentliche Darstellung.
Aber egal. Wenn Sie testen möchten, privaten oder internen Zugriffs -, Visual Studio-Test-Projekte können in der Regel generieren von accessor-Wrapper für Sie.
Sie würde rufen Sie die accessor-ctor statt der normalen ctor der Klasse. Wenn Sie dies tun, können Sie auf alle privaten oder internen Methoden/Eigenschaften der Instanz.
Finden Sie weitere Informationen über die generierten Typen hier: http://msdn.microsoft.com/en-us/library/bb385974(v=vs. 100).aspx
:edit: nach der Diskussion habe ich ein Beispiel für Sie wie moq zusammen mit der Einheit und UnityAutoMoq (3 verschiedene Nugets).
Lets sagen, dass Ihre Klasse sieht wie folgt aus:
Um dies zu testen können Sie mock es so:
InternalsVisibleTo
ist hilfreich. Ich möchte, um den Zugriff auf Interna der Versammlung, und nicht den Zugang zu anderen Baugruppen. Das ist so standardmäßig, aber jetzt muss ich zu verbergen, die Klasse hinter einem interface für die Prüfung, die können Sie nicht haben den internen Zugriff Planer.