Metodi interni di unit testing in VS2017 .Net Standard library


150

Attualmente sto giocando con l'ultimo Candidato di rilascio di Visual Studio 2017 creando una libreria .Net Standard 1.6. Sto usando xUnit per testare l'unità del mio codice e mi chiedevo se è ancora possibile testare metodi interni in VS2017.

Ricordo che potevi tutta una linea AssemblyInfo.cs in VS2015 che avrebbe permesso a progetti specifici di vedere metodi interni

[assembly:InternalsVisibleTo("MyTests")]

Dato che non esiste alcuna classe AssemblyInfo.cs in VS2017. Progetti standard netti mi chiedevo se fosse ancora possibile testare i metodi interni?


3
Si dovrebbe essere in grado di unit test il codice da funzionalità esternamente visibile solo. Dopotutto, se nessun percorso logico dal codice esterno può raggiungere quei metodi interni, allora cosa farebbero lì?
David,

3
@David Posso e ho fatto questo, ma in precedenza ho messo semplici test unitari su alcune classi interne. Giusto per essere più espliciti nei test.
Phil Murray,

5
AFAIK, puoi posizionare questo attributo in qualsiasi altro file, al di fuori del namespaceblocco, e dovrebbe essere compilato. Non dovrebbe esserci nulla di magico AssemblyInfo.cs. Non funziona? Naturalmente, è necessario aggiungere la usingclausola corretta o utilizzare l'attributo completo [assembly: System.Runtime.CompilerServices.InternalsVisibleTo("Something")].
Groo,

1
@ David Se si sta creando una biblioteca con le classi interne e avete bisogno di testare e deridere queste classi, InternalsVisibleToè fondamentale - ad esempio qui - stackoverflow.com/a/17574183/43453
PandaWood

Risposte:


210

Secondo i documenti .NET perInternalsVisibleToAttribute :

L'attributo viene applicato a livello di assieme. Ciò significa che può essere incluso all'inizio di un file di codice sorgente o può essere incluso nel file AssemblyInfo in un progetto Visual Studio.

In altre parole, puoi semplicemente inserirlo nel tuo file .cs con nome arbitrario e dovrebbe funzionare bene:

// some .cs file included in your project
using System.Runtime.CompilerServices;
[assembly:InternalsVisibleTo("MyTests")]

1
@PhilMurray: inoltre, sembra che ci sia un'impostazione che dovrebbe permetterti di creare un AssemblyInfo.csfile "classico" come spiegato qui . Altrimenti tutti gli attributi come "descrizione", "copyright" e altre cose vengono memorizzati nel file .csproj.
Groo,

43

Come descritto qui:

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

È possibile aggiungere l'attributo visibile interno nel file di progetto aggiungendo un altro ItemGroup:

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

o anche:

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

Mi piace quella soluzione perché il file di progetto sembra essere il posto giusto per definire tali preoccupazioni.


8

Mentre la prima risposta è perfettamente soddisfacente. Se ritieni di voler continuare a farlo nell'originale AssemblyInfo, puoi sempre scegliere di non generare automaticamente il file e aggiungerlo manualmente.

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

Per maggiori informazioni: https://stackoverflow.com/a/47075759/869033


5

L'attributo "InternalsVisibleTo" è la chiave per qualsiasi tipo di test "white-box" (il termine del decennio, immagino) per .Net. Può essere inserito in qualsiasi file c # con l'attributo "assembly" sul davanti. Si noti che i DOC MS affermano che il nome dell'assembly deve essere qualificato dal token della chiave pubblica, se è firmato. A volte non funziona e si deve usare la chiave pubblica completa al suo posto. L'accesso agli interni è la chiave per testare i sistemi concorrenti e in molte altre situazioni. Vedi https://www.amazon.com/xUnit-Test-Patterns-Refactoring-Code/dp/0131495054 . In questo libro, Meszaros descrive una varietà di stili di codifica che fondamentalmente costituiscono un approccio "Design For Test" allo sviluppo del programma. Almeno è così che l'ho usato nel corso degli anni.

AGGIUNTO: Mi dispiace, non sono qui da un po '. Un approccio è chiamato l'approccio "testing subclass" di Meszaros. Ancora una volta, si deve usare "internalsvisableto" per accedere agli interni della classe base. Questa è un'ottima soluzione, ma non funziona per le classi sigillate. Quando insegno "Design For Test", suggerisco che sia una delle cose che devono essere "preingegnerizzate" nelle classi di base per fornire testabilità. Deve diventare quasi una cosa culturale. Progettare una classe base "base" non sigillata. Chiamalo UnsealedBaseClass o qualcosa di uniformemente riconoscibile. Questa è la classe da sottoclassare per il test. Viene inoltre suddiviso in sottoclassi per costruire la classe di produzione sigillata, che spesso differisce solo nei costruttori che espone. Lavoro nel settore nucleare e i requisiti di prova sono presi MOLTO seriamente. Quindi, devo pensare a queste cose tutto il tempo. A proposito, lasciare hook di test nel codice di produzione non è considerato un problema nel nostro campo, purché siano "interni" in un'implementazione .Net. Le conseguenze di NON testare qualcosa possono essere abbastanza profonde.


1

Un altro modo è quello di utilizzare una classe pubblica TestMyFoo 'wrapper' all'interno del progetto target che ha metodi pubblici ed ereditari dalla classe che è necessario testare (ad esempio MyFoo). Questi metodi pubblici richiamano semplicemente la classe base che si desidera verificare.

Non è "ideale" quando finisci per spedire un gancio di prova nel tuo progetto di destinazione. Ma considera le moderne auto affidabili con porte diagnostiche e moderne apparecchiature elettroniche affidabili con una connessione JTAG. Ma nessuno è abbastanza sciocco da guidare la propria auto utilizzando la porta diagnostica.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.