Testowanie jednostkowe metod wewnętrznych w bibliotece VS2017 .Net Standard

150

Obecnie bawię się najnowszym Visual Studio 2017 Release Candidate, tworząc bibliotekę .Net Standard 1.6. Używam xUnit do testowania jednostkowego mojego kodu i zastanawiałem się, czy nadal możesz testować metody wewnętrzne w VS2017.

Pamiętam, że w VS2015 można było utworzyć całą linię klasy AssemblyInfo.cs, która umożliwiłaby określonym projektom wyświetlanie metod wewnętrznych

[assembly:InternalsVisibleTo("MyTests")]

Ponieważ w projektach VS2017 .Net Standard nie ma klasy AssemblyInfo.cs, zastanawiałem się, czy nadal możesz testować wewnętrzne metody jednostkowe?

Phil Murray
źródło
3
Państwo powinno być w stanie przetestować urządzenie kodzie od samego zewnętrznie widoczny funkcjonalności. W końcu, jeśli żadna logiczna ścieżka z zewnętrznego kodu nie może dotrzeć do tych wewnętrznych metod, to co by one tam w pierwszej kolejności robiły?
David
3
@David Mogłem i zrobiłem to, ale wcześniej umieściłem proste testy jednostkowe wokół niektórych klas wewnętrznych. Żeby było bardziej jednoznacznie w testowaniu.
Phil Murray,
5
AFAIK, możesz umieścić ten atrybut w dowolnym innym pliku, poza namespaceblokiem i powinien się skompilować. Nie powinno być w tym nic magicznego AssemblyInfo.cs. Czy to nie działa? Oczywiście musisz dodać właściwą usingklauzulę lub użyć w pełni kwalifikowanego atrybutu [assembly: System.Runtime.CompilerServices.InternalsVisibleTo("Something")].
Groo,
1
@David Jeśli tworzysz bibliotekę z wewnętrznymi klasami i musisz testować i mockować te klasy, InternalsVisibleTojest to krytyczne - np. Tutaj - stackoverflow.com/a/17574183/43453
PandaWood

Odpowiedzi:

210

Zgodnie z dokumentacją .NET dlaInternalsVisibleToAttribute :

Atrybut jest stosowany na poziomie zespołu. Oznacza to, że można go dołączyć na początku pliku kodu źródłowego lub można go dołączyć do pliku AssemblyInfo w projekcie programu Visual Studio.

Innymi słowy, możesz po prostu umieścić go w swoim własnym pliku .cs o dowolnej nazwie i powinno działać dobrze:

// some .cs file included in your project
using System.Runtime.CompilerServices;
[assembly:InternalsVisibleTo("MyTests")]
Groo
źródło
1
@PhilMurray: wydaje się również, że istnieje ustawienie, które powinno pozwolić na utworzenie „klasycznego” AssemblyInfo.cspliku, jak wyjaśniono tutaj . W przeciwnym razie wszystkie atrybuty, takie jak „opis”, „prawa autorskie” i inne, zostaną zapisane w pliku .csproj.
Groo,
43

Jak opisano tutaj:

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

Możliwe jest dodanie wewnętrznego widocznego atrybutu w pliku projektu poprzez dodanie kolejnej ItemGroup:

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

lub nawet:

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

Podoba mi się to rozwiązanie, ponieważ plik projektu wydaje się być właściwym miejscem do definiowania takich problemów.

JanDotNet
źródło
8

Podczas gdy pierwsza odpowiedź jest całkowicie w porządku. Jeśli uważasz, że nadal chcesz to zrobić w oryginale AssemblyInfo, zawsze możesz wybrać, aby nie generować automatycznie pliku i dodać go ręcznie.

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

Więcej informacji: https://stackoverflow.com/a/47075759/869033

Nick N.
źródło
5

Atrybut „InternalsVisibleTo” jest kluczem do wszelkiego rodzaju testów typu „biała skrzynka” (myślę, że to dziesięciolecie) dla domeny .Net. Można go umieścić w dowolnym pliku C # z atrybutem „assembly” na początku. Zauważ, że MS DOC mówią, że nazwa zestawu musi być kwalifikowana przez token klucza publicznego, jeśli jest podpisany. Czasami to nie działa i trzeba w jego miejscu użyć pełnego klucza publicznego. Dostęp do elementów wewnętrznych jest kluczem do testowania systemów współbieżnych oraz w wielu innych sytuacjach. Zobacz https://www.amazon.com/xUnit-Test-Patterns-Refactoring-Code/dp/0131495054 . W tej książce Meszaros opisuje różnorodne style kodowania, które zasadniczo składają się na podejście do tworzenia programu „Design For Test”. Przynajmniej tak go używałem przez lata.

DODANO: Przepraszam, nie byłem tu przez jakiś czas. Jedno podejście jest nazwane przez Meszarosa podejściem „podklasy testowania”. Ponownie, należy użyć „internalsvisableto”, aby uzyskać dostęp do elementów wewnętrznych klasy bazowej. To świetne rozwiązanie, ale nie działa w przypadku klas zamkniętych. Kiedy uczę „Design For Test”, sugeruję, że jest to jedna z rzeczy, które muszą być „wstępnie zaprojektowane” w klasach bazowych, aby zapewnić testowalność. To musi stać się niemal kulturową rzeczą. Zaprojektuj „podstawową” klasę bazową, która jest rozpieczętowana. Nazwij to UnsealedBaseClass lub czymś jednolicie rozpoznawalnym. To jest klasa, która ma być podklasa do testowania. Jest również podklasą, aby zbudować zapieczętowaną klasę produkcyjną, która często różni się tylko konstruktorami, które eksponuje. Pracuję w przemyśle nuklearnym i wymagania testowe są BARDZO poważnie traktowane. Więc muszę cały czas o tym myśleć. Nawiasem mówiąc, pozostawienie haków testowych w kodzie produkcyjnym nie jest uważane za problem w naszej dziedzinie, o ile są one „wewnętrzne” w implementacji .Net. Konsekwencje NIE testowania czegoś mogą być dość głębokie.

kurt.matis
źródło
1

Innym sposobem jest użycie „opakowującej” klasy publicznej TestMyFoo wewnątrz projektu docelowego, która ma publiczne metody i dziedziczy z klasy, którą chcesz przetestować (np. MyFoo). Te metody publiczne po prostu wywołują klasę bazową, którą chcesz przetestować.

To nie jest „idealne”, ponieważ kończy się wysyłaniem haka testowego w docelowym projekcie. Ale weźmy pod uwagę nowoczesne niezawodne samochody z portami diagnostycznymi i nowoczesną niezawodną elektronikę z połączeniem JTAG. Ale nikt nie jest na tyle głupi, żeby prowadzić swój samochód przez port diagnostyczny.

pasztet andrewski
źródło