Birim testi yaparken C # “dahili” erişim değiştirici


469

Birim testinde yeniyim ve daha fazla 'dahili' erişim değiştirici kullanmaya başlayıp başlamayacağımı anlamaya çalışıyorum. 'İnternal' kullanırsak ve 'InternalsVisibleTo' derleme değişkenini ayarlarsak, test projesinden herkese açıklamak istemediğimiz işlevleri test edebileceğimizi biliyorum. Bu beni her zaman 'iç' kullanmam gerektiğini düşündürüyor çünkü en azından her projenin kendi test projesi var. Bana bunu neden yapmamam gerektiğini söyleyebilir misiniz? Ne zaman 'özel' kullanmalıyım?


1
Bahsetmeye değer - genellikle yöntemlerin System.Diagnostics.Debug.Assert()içinde kullanarak dahili yöntemlerinizi birim test etme ihtiyacından kaçınabilirsiniz .
Mike Marynowski

Yanıtlar:


1195

İç sınıfların test edilmesi gerekir ve bir montaj niteliği vardır:

using System.Runtime.CompilerServices;

[assembly:InternalsVisibleTo("MyTests")]

Bunu proje bilgi dosyasına ekleyin, örn Properties\AssemblyInfo.cs.


70
Test edilen projeye ekleyin (örneğin, Properties \ AssemblyInfo.cs dosyasında). "MyTests" test düzeneği olacaktır.
EricSchaefer

86
Bu gerçekten kabul edilen cevap olmalı. Sizi bilmiyorum çocuklar, ama testler test ettikleri koddan "çok uzakta" olduğunda sinirlenmeye eğilimliyim. Tamam olarak işaretlenmiş herhangi bir şeyi test etmekten kaçınıyorum private, ancak çok fazla privateşey internalçıkarılmakta zorlanan bir sınıfa işaret edebilir . TDD veya TDD yok, aynı kodu kullanan birkaç testten daha fazla kodu test eden daha fazla teste sahip olmayı tercih ederim. Ve bir internalşeyleri test etmekten kaçınmak, iyi bir oran elde etmeye tam olarak yardımcı olmaz.
sm

7
@DerickBailey ve Dan Tao arasında ve özel arasındaki anlamsal fark ve bileşenleri test etme ihtiyacı konusunda büyük bir tartışma var . Okunmaya değer.
Kris McGinnes

31
Ve bloğuna kaydırma #if DEBUG, #endifbu seçeneği yalnızca hata ayıklama yapılarında etkinleştirir.
Gerçek Edward Cullen

17
Bu doğru cevap. Sadece genel yöntemlerin birim test edilmesi gerektiğini söyleyen cevaplarda birim testlerin noktasında eksiklik ve mazeret bulunmuyor. Fonksiyonel test kara kutu yönelimlidir. Birim testleri beyaz kutu yönelimlidir. Yalnızca ortak API'ları değil, işlevsellik "birimlerini" test etmelidirler.
Gunnar

127

Eğer özel yöntemler test etmek istiyorsanız, bir göz PrivateObjectve PrivateTypeiçinde Microsoft.VisualStudio.TestTools.UnitTestingad. Gerekli yansıma kodu etrafında kullanımı kolay sarmalayıcılar sunarlar.

Dokümanlar: PrivateType , PrivateObject

VS2017 ve 2019 için, bunları MSTest'i indirerek bulabilirsiniz.


15
Oy vermede lütfen yorum bırakın. Teşekkürler.
Brian Rasmussen

35
Bu cevabı oylamak aptalca. Daha önce bahsedilmeyen yeni bir çözüme ve gerçekten iyi bir çözüme işaret ediyor.
Ignacio Soler Garcia

Görünüşe göre, TestFramework'u uygulama hedeflemesi için .net2.0 veya daha yeni bir sürümle ilgili bazı sorunlar var: github.com/Microsoft/testfx/issues/366
Johnny Wu

41

Eric'in cevabına ek olarak, bunu csprojdosyada da yapılandırabilirsiniz :

<ItemGroup>
    <AssemblyAttribute Include="System.Runtime.CompilerServices.InternalsVisibleTo">
      <_Parameter1>MyTests</_Parameter1>
    </AssemblyAttribute>
</ItemGroup>

Veya test edilecek proje başına bir test projeniz varsa, Directory.Build.propsdosyanızda şöyle bir şey yapabilirsiniz :

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

Bkz. Https://stackoverflow.com/a/49978185/1678053
Örnek: https://github.com/gldraphael/evlog/blob/master/Directory.Build.props#L5-L12


2
Bu en iyi cevap imo olmalı. Diğer tüm yanıtlar çok eski .net derleme bilgisinden uzaklaşıyor ve işlevselliği csproj tanımlarına taşıyor.
mBrice1024

12

Varsayılan olarak gizli kullanmaya devam edin. Bir üye bu türden daha fazla maruz kalmamalıysa, aynı proje içinde bile bu türden daha fazla maruz bırakılmamalıdır. Bu, işleri daha güvenli ve daha düzenli tutar - nesneyi kullanırken, hangi yöntemleri kullanabileceğiniz daha açıktır.

Bunu söyledikten sonra, doğal olarak özel yöntemleri bazen test amacıyla dahili hale getirmenin makul olduğunu düşünüyorum. Bunu yeniden düzenleme-düşmanca olan yansımayı kullanmayı tercih ederim.

Dikkate alınması gereken bir şey bir "ForTest" soneki olabilir:

internal void DoThisForTest(string name)
{
    DoThis(name);
}

private void DoThis(string name)
{
    // Real implementation
}

Daha sonra sınıfı aynı projede kullandığınızda, (şimdi ve gelecekte) bu yöntemi gerçekten kullanmamanız gerektiği açıktır - sadece test amaçlıdır. Bu biraz hileli ve kendim yaptığım bir şey değil, ama en azından dikkate değer.


2
Yöntem dahili ise bu, test düzeneğinden kullanılmasını engellemez mi?
Ralph Shillington

7
Zaman zaman ForTestyaklaşımı kullanıyorum ama her zaman çirkin buluyorum (üretim iş mantığı açısından gerçek bir değer sağlamayan kod ekleyerek). Genellikle bu yaklaşımı kullanmak zorunda kaldım çünkü tasarım biraz talihsiz (yani testler arasında tekil örnekleri sıfırlamak zorunda)
ChrisWue

1
Bunu düşürmek için cazip - bu kesmek ve sadece sınıfı özel yerine dahili yapmak arasındaki fark nedir? En azından derleme koşulları ile. Sonra gerçekten dağınık oluyor.
CAD bloke

6
@CADbloke: Yöntemi özel değil dahili yapmak mı demek istediniz ? Aradaki fark, gerçekten özel olmasını istediğinizin açık olmasıdır . Bir yöntemini çağıran üretim kodu tabanında içindeki her kod ForTestolduğu besbelli sadece yöntem iç yaparsanız kullanımına 's cezası benziyor oysa yanlış.
Jon Skeet

2
@CADbloke: Bir sürüm derlemesindeki tek tek yöntemleri, kısmi sınıflar olan IMO ile aynı dosyada kolayca kolayca hariç tutabilirsiniz. Eğer Ve eğer bunu yapmak, onu hemen bana kötü bir fikir gibi geliyor senin sürüm oluşturma, karşı testler değiliz düşündürmektedir.
Jon Skeet

11

Özel'i de kullanabilirsiniz ve özel yöntemleri yansıma ile çağırabilirsiniz. Visual Studio Team Suite kullanıyorsanız, sizin için özel yöntemlerinizi çağırmak için bir proxy oluşturacak bazı güzel işlevlere sahiptir. Özel ve korumalı yöntemleri birim test etmek için işi nasıl yapabileceğinizi gösteren bir kod projesi makalesi:

http://www.codeproject.com/KB/cs/testnonpublicmembers.aspx

Hangi erişim değiştiriciyi kullanmanız gerektiği konusunda, genel kuralım özel ile başlar ve gerektiği gibi yükselir. Bu şekilde, sınıfınızın iç detaylarını gerçekten ihtiyaç duyulduğu kadar az göstereceksiniz ve uygulama ayrıntılarını olması gerektiği gibi gizli tutmaya yardımcı olur.


3

Ben kullanıyorum Dotnet 3.1.101ve .csprojbenim için çalışan eklemeler vardı:

<PropertyGroup>
  <!-- Explicitly generate Assembly Info -->
  <GenerateAssemblyInfo>true</GenerateAssemblyInfo>
</PropertyGroup>

<ItemGroup>
  <AssemblyAttribute Include="System.Runtime.CompilerServices.InternalsVisibleToAttribute">
  <_Parameter1>MyProject.Tests</_Parameter1>
  </AssemblyAttribute>
</ItemGroup>

Umarım bu birisine yardım eder!


1
Açıkça bir araya getirilmiş montaj bilgilerinin eklenmesi, sonunda benim için de işe yarayan şeydi. Bunu gönderdiğiniz için teşekkür ederiz!
thevioletsaber
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.