Interne Methoden zum Testen von Einheiten in der VS2017 .Net Standard-Bibliothek

150

Ich spiele derzeit mit dem neuesten Visual Studio 2017 Release Candidate, indem ich eine .Net Standard 1.6-Bibliothek erstelle. Ich verwende xUnit zum Unit-Test meines Codes und habe mich gefragt, ob Sie noch interne Methoden in VS2017 testen können.

Ich erinnere mich, dass Sie alle eine Zeile AssemblyInfo.cs-Klasse in VS2015 verwenden könnten, die es bestimmten Projekten ermöglichen würde, interne Methoden anzuzeigen

[assembly:InternalsVisibleTo("MyTests")]

Da es in VS2017 .Net Standard-Projekten keine AssemblyInfo.cs-Klasse gibt, habe ich mich gefragt, ob Sie noch interne Methoden als Unit-Test durchführen können.

Phil Murray
quelle
3
Sie sollten in der Lage sein, Ihren Code nur anhand von extern sichtbaren Funktionen zu testen. Wenn kein logischer Pfad von externem Code diese internen Methoden erreichen kann, was würden sie dann überhaupt dort tun?
David
3
@ David Ich kann und habe dies getan, aber ich habe zuvor einfache Unit-Tests für einige interne Klassen durchgeführt. Nur um beim Testen expliziter zu sein.
Phil Murray
5
AFAIK, Sie können dieses Attribut in jeder anderen Datei außerhalb des namespaceBlocks platzieren und es sollte kompiliert werden. Es sollte nichts Magisches sein AssemblyInfo.cs. Funktioniert es nicht Natürlich müssen Sie die richtige usingKlausel hinzufügen oder das vollständig qualifizierte Attribut verwenden [assembly: System.Runtime.CompilerServices.InternalsVisibleTo("Something")].
Groo
1
@ David Wenn Sie eine Bibliothek mit internen Klassen erstellen und diese Klassen testen und verspotten müssen, InternalsVisibleToist dies kritisch - z. B. hier - stackoverflow.com/a/17574183/43453
PandaWood

Antworten:

209

Laut .NET-Dokumenten fürInternalsVisibleToAttribute :

Das Attribut wird auf Baugruppenebene angewendet. Dies bedeutet, dass es am Anfang einer Quellcodedatei oder in der AssemblyInfo-Datei in einem Visual Studio-Projekt enthalten sein kann.

Mit anderen Worten, Sie können es einfach in Ihre eigene, willkürlich benannte .cs-Datei einfügen, und es sollte einwandfrei funktionieren:

// some .cs file included in your project
using System.Runtime.CompilerServices;
[assembly:InternalsVisibleTo("MyTests")]
Groo
quelle
1
@PhilMurray: Es scheint auch eine Einstellung zu geben, mit der Sie eine "klassische" AssemblyInfo.csDatei erstellen können, wie hier erläutert . Andernfalls werden alle Attribute wie "Beschreibung", "Copyright" und andere Elemente in der .csproj-Datei gespeichert.
Groo
43

Wie hier beschrieben:

https://blog.sanderaernouts.com/make-internals-visible-with-new-csproj-format

Sie können das interne sichtbare Attribut in der Projektdatei hinzufügen, indem Sie eine weitere ItemGroup hinzufügen:

<ItemGroup>
    <AssemblyAttribute Include="System.Runtime.CompilerServices.InternalsVisibleTo">
        <_Parameter1>$(AssemblyName).Tests</_Parameter1>
    </AssemblyAttribute>
</ItemGroup>

oder auch:

<ItemGroup>
    <AssemblyAttribute Include="System.Runtime.CompilerServices.InternalsVisibleTo">
        <_Parameter1>$(MSBuildProjectName).Tests</_Parameter1>
    </AssemblyAttribute>
</ItemGroup>

Ich mag diese Lösung, weil die Projektdatei der richtige Ort zu sein scheint, um solche Bedenken zu definieren.

JanDotNet
quelle
8

Während die erste Antwort vollkommen in Ordnung ist. Wenn Sie der Meinung sind, dass Sie dies dennoch im Original tun möchten, AssemblyInfokönnen Sie jederzeit festlegen, dass die Datei nicht automatisch generiert und manuell hinzugefügt wird.

<PropertyGroup>
   <GenerateAssemblyInfo>false</GenerateAssemblyInfo>
</PropertyGroup>

Weitere Informationen: https://stackoverflow.com/a/47075759/869033

Nick N.
quelle
5

Das Attribut "InternalsVisibleTo" ist der Schlüssel für jede Art von "White-Box" -Test (der Begriff des Jahrzehnts, denke ich) für .Net. Es kann in eine beliebige c # -Datei mit dem Attribut "Assembly" auf der Vorderseite eingefügt werden. Beachten Sie, dass MS-DOCs angeben, dass der Assemblyname durch das Token für den öffentlichen Schlüssel qualifiziert werden muss, wenn er signiert ist. Manchmal funktioniert das nicht und man muss den vollständigen öffentlichen Schlüssel an seiner Stelle verwenden. Der Zugriff auf Interna ist der Schlüssel zum Testen gleichzeitiger Systeme und in vielen anderen Situationen. Siehe https://www.amazon.com/xUnit-Test-Patterns-Refactoring-Code/dp/0131495054 . In diesem Buch beschreibt Meszaros eine Vielzahl von Codierungsstilen, die im Grunde genommen einen "Design For Test" -Ansatz für die Programmentwicklung darstellen. Zumindest habe ich es über die Jahre so benutzt.

ADDED: Entschuldigung, ich war schon eine Weile nicht mehr hier. Ein Ansatz wird von Meszaros als "Testunterklassen" -Ansatz bezeichnet. Wieder muss man "internalsvisableto" verwenden, um auf die Interna der Basisklasse zuzugreifen. Dies ist eine großartige Lösung, funktioniert jedoch nicht für versiegelte Klassen. Wenn ich "Design for Test" unterrichte, schlage ich vor, dass dies eines der Dinge ist, die in den Basisklassen "vorentwickelt" werden müssen, um Testbarkeit zu gewährleisten. Es muss fast eine kulturelle Sache werden. Entwerfen Sie eine Basisklasse "Basis", die nicht versiegelt ist. Nennen Sie es UnsealedBaseClass oder etwas einheitlich Erkennbares. Dies ist die Klasse, die zum Testen in Unterklassen unterteilt werden soll. Es wird auch in Unterklassen unterteilt, um die produktionsversiegelte Klasse zu erstellen, die sich häufig nur in den Konstruktoren unterscheidet, die sie verfügbar macht. Ich arbeite in der Nuklearindustrie und die Testanforderungen werden SEHR ernst genommen. Also muss ich die ganze Zeit über diese Dinge nachdenken. Das Belassen von Test-Hooks im Produktionscode wird in unserem Bereich übrigens nicht als Problem angesehen, solange sie in einer .Net-Implementierung "intern" sind. Die Konsequenzen, etwas NICHT zu testen, können sehr tiefgreifend sein.

kurt.matis
quelle
1

Eine andere Möglichkeit besteht darin, eine öffentliche 'Wrapper'-TestMyFoo-Klasse innerhalb des Zielprojekts zu verwenden, die öffentliche Methoden und Vererbungen von der zu testenden Klasse enthält (z. B. MyFoo). Diese öffentlichen Methoden rufen einfach die Basisklasse auf, die Sie testen möchten.

Es ist nicht "ideal", da Sie am Ende einen Testhaken in Ihrem Zielprojekt versenden. Betrachten Sie jedoch moderne zuverlässige Autos mit Diagnoseanschlüssen und moderne zuverlässige Elektronikschiffe mit JTAG-Verbindung. Aber niemand ist dumm genug, sein Auto über den Diagnoseanschluss zu fahren.

Andrew Pate
quelle