Wir haben eine Business Logic Layer (BLL), die eng mit unserer Datenzugriffsschicht (DAL) verbunden ist. Wir telefonieren wie folgt:
using (FooData data = new FooData())
{
data.DoSomething();
}
Es ist wichtig zu beachten, dass sich alle unsere Datenklassen internal
in derselben Assembly wie die Logikklassen befinden, sodass nur die BLL auf die DAL zugreifen kann.
Um diese zu entkoppeln (um das Testen von Einheiten zu erleichtern), besteht eine Idee darin, IDataClass-Schnittstellen wie IFooData zu erstellen. Zuerst dachte ich, dass es ein Problem sein könnte, weil wir unsere Datenklassen öffentlich machen müssten, um die Schnittstellen zu implementieren. Aber wir sollten in der Lage sein, die Datenklassen intern zu halten, obwohl wir immer noch die Methoden benötigen, um öffentlich zu sein:
public interface IFooData
{
void DoSomething();
}
internal class FooData : IFooData // Notice the class is internal
{
public void DoSomething(); // Method is public, but that's ok because class is internal
}
Obwohl die Methode öffentlich ist, sollten wir, da die Klasse selbst intern ist, nur unseren BLL-Zugriff zulassen.
Stimmt etwas an diesem Ansatz nicht? Gibt es eine bessere Möglichkeit, die DAL für Unit-Tests zu abstrahieren, ohne die DAL für die Welt zu öffnen, indem sie veröffentlicht wird?
quelle
Antworten:
Das Extrahieren einer Schnittstelle und das Sicherstellen, dass die BLL nur Schnittstellentypen verwendet, ist ein guter Weg, um die BLL ohne die Datenbank testbar zu machen.
Was Sie tun, ist absolut in Ordnung.
quelle
using (IFooData data = new FooData())
in Ihrer BLL befindet, haben Sie außer der Einführung der Benutzeroberfläche keine wirklichen Änderungen vorgenommen. Sie müssen jetzt einen Weg finden, um dasIFooData
externe zu instanziieren , sonst werden Ihre BLL-Tests weiterhin mit dem DAL gekoppelt.DataAccessFactory.GetDataInterface<IFooData>().DoSomething();
Sie können die
InternalsVisibleToAttribute
verwenden, um Ihre DAL aus Ihrer Business-Schicht herauszubrechen, aber die DAL-Methoden weiterhin intern zu halten. Am Ende erstellen Sie Ihre DAL als Freund-Assembly .Dies ist möglicherweise kein guter Ansatz, da Sie in der
Assembly.cs
Datei Ihres DAL angeben müssen, welche Assemblys auf den DAL zugreifen können. Es handelt sich also immer noch um eine Kopplung (DAL weiß etwas über BLL).Um Ihre Frage zu beantworten, ist an Ihrem Ansatz nichts auszusetzen. Die Nutzung von Friend-Assemblys kann Ihnen jedoch ein wenig mehr Abstraktion bieten und Ihnen wahrscheinlich dabei helfen, Ihren Code testbarer zu machen.
Ich hoffe das hilft.
quelle
InternalsVisibleTo
, und wenn ich den DAL auf eine andere Baugruppe verschieben muss, würde das in der Tat helfen.Sie scheinen unbeweglich in Bezug auf Ihre Ideen zu sein, die Sie in Ihrer Frage dargelegt haben, aber ich werde trotzdem eine Antwort geben - jemand könnte sie irgendwann in der Zukunft nützlich finden.
Wenn Sie darauf bestehen, Ihr DAL intern zu halten, es aber dennoch mit einigen Komponententests erreichen möchten und die Microsoft Unit Testing-Tools nicht verwenden möchten , versuchen Sie es mit dem PrivateObject- Ansatz. Dies ist ein Wrapper zum Nachdenken, den Sie jederzeit selbst codieren können, der Ihnen jedoch einige Zeilen beim Schreiben erspart.
Beachten Sie, dass InternalsVisibleTo Verwendung ist ein gangbarer Weg, aber es ist ungeschickt - wenn Sie es verwenden , dann können Sie bereits bergab auf einem schnellen Schlitten sein.
internal
bedeutet, dass etwas nur innerhalb der Grenzen seiner Assembly öffentlich ist. Dieser Modifikator wird normalerweise verwendet, weil Sie nicht möchten, dass Inhalte von außen verwendet werden könnenDiese Versammlung, dann drehen Sie sich sofort um und verletzen dieses Konzept, indem Sie ein InternalsVisibleTo ... deklarieren, das eine große schmutzige rote Fahne ist, die nach einem Refactoring schreit. Das Entkoppeln ist Zeitverschwendung, wenn nur eine Baugruppe die andere aufruft. Sie können sie auch zusammenkleben. Die Entkopplung lässt darauf schließen, dass mehrere Assemblys das Ziel aufrufen (die Einführung von Unit-Tests zählt nicht für das "Multiple", da es Möglichkeiten gibt, zur Ziel-Assembly zu gelangen, wie ich bereits erwähnt habe).quelle
InternalsVisibleTo
. Ich benutze es nicht. Aus irgendeinem Grund nehmen Sie an, dass ich es benutze. Ich verstehe nicht warum.Technisch ist an Ihrem Design nichts auszusetzen.
Ich würde jedoch einen alternativen Ansatz in Betracht ziehen: Anstatt Ihre BLL von Ihrer DAL zu entkoppeln, sollten Sie Ihre DAL besser von Ihrer Datenbank entkoppeln. Ermöglichen Sie die Erstellung von DAL-Objekten im Speicher. Wenn Ihre BLL DAL-Objekte von irgendwoher laden muss, verwenden Sie das Repository-Muster (siehe hier ), um einen direkten Kontakt der BLL mit der Datenbank zu vermeiden. Auf diese Weise können Sie
Was Sie verlieren, ist die Fähigkeit, die BLL mit DAL-Mocks zu testen. In der Realität sehen diese DAL-Scheinobjekte jedoch in der Regel Ihren echten DAL-Objekten sehr ähnlich, um eine Grundlage für nützliche Tests der BLL zu bieten. IMHO vermeidet es viel Code-Duplizierung und unnötigen Aufwand, wenn Sie Ihre realen DAL-Objekte für automatisierte Tests der BLL wiederverwenden.
quelle
Der Schnittstellenansatz ist ein guter / allgemeiner Ansatz, um Ihre DAL beim Testen von Verbrauchern wie der BLL zu verspotten.
Beachten Sie jedoch, dass Sie durch die interne Erstellung Ihrer DAL-Betonklassen möglicherweise die direkte Prüfung Ihrer konkreten DAL erschweren, da dies jetzt impliziert, dass Ihre DAL-Komponententests auch in dieser Baugruppe durchgeführt werden müssen, ohne dass Hintertüren verwendet werden müssen wie Reflexion.
Außerdem können Sie zu einem späteren Zeitpunkt in Betracht ziehen, einen IoC-Container zu verwenden, um die Implementierung hinter einer Schnittstelle aufzubauen, die möglicherweise auch auf der internen Schnittstelle ausgelöst wird.
Sie können die Kapselung nachahmen, die Sie mit "nur intern" erreichen möchten, indem Sie eine Konvention / LINT-Regel hinzufügen, die Ihre BLL / andere Ebenen über die Schnittstelle mit der DAL koppeln müssen, nicht über die konkrete Implementierung.
quelle