ユニットテストを実行するときのC#の「内部」アクセス修飾子


469

私はユニットテストの初心者です。「内部」アクセス修飾子をもっと使い始める必要があるかどうかを考えています。'internal'を使用してアセンブリ変数 'InternalsVisibleTo'を設定すると、テストプロジェクトからpublicを宣言したくない関数をテストできることを知っています。少なくとも各プロジェクトには(独自に)テストプロジェクトがあるので、常に「内部」を使用するだけでよいと考えます。私がこれをしてはいけない理由を教えてくれませんか?いつ「プライベート」を使用すればよいですか?


1
言及する価値があります-多くの場合System.Diagnostics.Debug.Assert()、メソッド自体の内部で使用することにより、内部メソッドのユニットテストの必要性を回避できます。
Mike Marynowski 2017年

回答:


1195

内部クラスをテストする必要があり、アセンブリ属性があります:

using System.Runtime.CompilerServices;

[assembly:InternalsVisibleTo("MyTests")]

これをプロジェクト情報ファイルに追加してくださいProperties\AssemblyInfo.cs


70
テスト中のプロジェクトに追加します(例:Properties \ AssemblyInfo.cs)。「MyTests」はテストアセンブリです。
EricSchaefer 2010

86
これは本当に受け入れられる答えになるはずです。私はあなたたちについては知りませんが、テストがコードから「遠すぎる」場合、彼らがテストしているときは緊張する傾向があります。私はすべて、とマークされたものをテストしないようprivateにしていますが、あまりにも多くのprivateものが、internal抽出に苦労しているクラスを指し示している可能性があります。TDDまたはTDDなしの場合、同じ量のコードを実行するいくつかのテストよりも、多くのコードをテストするより多くのテストを行うことを好みます。そして、ものをテストするinternalことを避けることは、良い比率を達成するために正確に助けにはなりません。
sm

7
@DerickBaileyとDan Taoの間では、内部プライベートのセマンティックの違い、および内部コンポーネントをテストする必要性について、すばらしい議論が行われています。読む価値があります。
クリス・マクギネス2014年

31
ブロックとをラップすると#if DEBUG#endifデバッグビルドでのみこのオプションが有効になります。
Real Edward Cullen 14

17
これが正解です。パブリックメソッドのみを単体テストする必要があるという答えは、単体テストの要点を欠いており、言い訳をすることになります。機能テストはブラックボックス指向です。ユニットテストはホワイトボックス指向です。パブリックAPIだけでなく、機能の「ユニット」をテストする必要があります。
Gunnar

127

あなたはプライベートメソッドをテストしたい場合は、見ていPrivateObjectPrivateTypeMicrosoft.VisualStudio.TestTools.UnitTesting名前空間を。必要なリフレクションコードの周りに使いやすいラッパーを提供します。

ドキュメント: PrivateTypePrivateObject

VS2017および2019の場合、MSTest.TestFramework nugetをダウンロードしてこれらを見つけることができます


15
投票するときはコメントを残してください。ありがとう。
Brian Rasmussen

35
この答えを投票するのは愚かなことです。それは新しい解決策と以前に言及されていない本当に良い解決策を指しています。
Ignacio Soler Garcia

どうやら、.net2.0以降をターゲットとするアプリにTestFrameworkを使用すると問題が発生する:github.com/Microsoft/testfx/issues/366
Johnny Wu

41

エリックの答えに加えて、csprojファイルでこれを構成することもできます。

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

または、テストするプロジェクトごとに1つのテストプロジェクトがある場合、Directory.Build.propsファイルで次のようなことを行うことができます。

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

参照:https : //stackoverflow.com/a/49978185/1678053
例:https : //github.com/gldraphael/evlog/blob/master/Directory.Build.props#L5-L12


2
これが一番の答えです。.netがアセンブリ情報から離れ、機能をcsproj定義に移動しているため、他のすべての回答は非常に古くなっています。
mBrice1024

12

デフォルトではプライベートを使用してください。メンバーがそのタイプを超えて公開されるべきではない場合、同じプロジェクト内であっても、そのタイプを超えて公開されるべきではありません。これにより、安全で整然とした状態が維持されます。オブジェクトを使用している場合は、使用できるメソッドが明確になります。

そうは言っても、自然にプライベートなメソッドを内部的にテスト目的で作成するのは合理的だと思います。リファクタリングに適さないリフレクションを使用する方が好きです。

考慮すべき1つのことは、 "ForTest"サフィックスです。

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

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

次に、同じプロジェクト内でクラスを使用している場合、このメソッドを実際に使用するべきではないことは明らかです(現在および将来)。テストの目的でのみ存在します。これは少しハックであり、私自身ではありませんが、少なくとも検討する価値はあります。


2
メソッドが内部である場合、これはテストアセンブリからの使用を排除しませんか?
Ralph Shillington

7
私は時々このForTestアプローチを使用しますが、私はいつもそれが醜いことに気づきます(本番ビジネスロジックの観点から実際の価値を提供しないコードを追加します)。設計が非常に不幸であるため(つまり、テスト間でシングルトンインスタンスをリセットする必要があるため)、通常、このアプローチを使用する必要がありました
ChrisWue

1
これに反対票を投じようとしています-このハックとクラスをプライベートではなく内部にするだけの違いは何ですか?まあ、少なくともコンパイル条件付き。その後、それは本当に厄介になります。
CADが2013年

6
@CADbloke:メソッドをプライベートではなく内部にするということですか?違いは、それを本当に非公開にしたいことは明らかだということです。メソッドを呼び出すプロダクションコードベース内のコードForTest明らかに間違っていますが、メソッドを内部的にするだけの場合は問題なく使用できます。
Jon Skeet 2013年

2
@CADbloke:リリースビルド内の個々のメソッドを、部分クラスIMOを使用するのと同じように同じファイルで簡単に除外できます。あなたがいる場合とやることをやる、それはあなたが私には悪いアイデアのように聞こえるあなたのリリースビルド、照らし合わせてテストを実行していないことを示唆しています。
Jon Skeet 2013年

11

プライベートも使用でき、リフレクションを使用してプライベートメソッドを呼び出すことができます。Visual Studio Team Suiteを使用している場合は、プライベートメソッドを呼び出すプロキシを生成する優れた機能がいくつかあります。以下は、プライベートメソッドと保護されたメソッドを単体テストするための作業を自分で行う方法を示すコードプロジェクトの記事です。

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

どのアクセス修飾子を使用する必要があるかについては、私の一般的な経験則は、プライベートから始めて、必要に応じてエスカレートすることです。そうすることで、クラスの内部の詳細を本当に必要なだけ公開し、実装の詳細を非表示にしておくことができます。


3

私が使用Dotnet 3.1.101.csprojていて、私のために働いた追加は次のとおりでした:

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

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

これが誰かに役立つことを願っています!


1
アセンブリ情報を明示的に生成することの追加は、私にとっても最終的に機能するものでした。これを投稿していただきありがとうございます!
thevioletsaber
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.