コードを内部に作成しますが、他のプロジェクトからのユニットテストに使用できます


129

すべての単体テストを独自のプロジェクトに入れます。単体テストのためだけに、内部ではなく特定のクラスを公開する必要があることがわかりました。とにかくこれを行う必要を避けるためにありますか?クラスを封印する代わりに公開することによるメモリの意味は何ですか?


回答:


205

.NETを使用している場合、InternalsVisibleToアセンブリ属性を使用すると、「フレンド」アセンブリを作成できます。これらは、他のアセンブリの内部クラスおよびメンバーへのアクセスが許可されている、厳密に名前が付けられた特定のアセンブリです。

これは、関連するアセンブリを密に結合するため、慎重に使用する必要があります。InternalsVisibleToの一般的な用途は、ユニットテストプロジェクトです。上記の理由により、実際のアプリケーションアセンブリでの使用にはおそらく適していません。

例:

[assembly: InternalsVisibleTo("NameAssemblyYouWantToPermitAccess")]
namespace NameOfYourNameSpace
{

23
#if DEBUGを属性の周りに置いて、デバッグでユニットテストを行うことをお勧めします。そうすれば、リリースコードに属性が設定されていないことを確認できます。
スティーブクック

これは単なるアイデアです。わかりません。...方法:#if DEBUG public class IniReader #else internal class IniReader #endifおそらくお勧めしませんか?どうして?
jmelhus 2013

4
さて、なぜテストをビルドのデバッグに限定するのですか?
Marco Mp 2015年

2
また、ちょっとしたコツだけで、「フレンド」アセンブリに厳密な名前を付ける必要はありません(私の個人的な好みがそうでなくても、必須ではありません)。
Marco Mp 2015年

9
同意しない。非常に薄いパブリックAPIを使用して複雑なコンポーネントを構築している場合、パブリックAPIを介してのみテストすることは非現実的で非現実的です。あなたは、手入れのできない泥の玉になってしまいます。代わりに、内部ユニットを慎重に定義し、個別にテストします。Jeremy D. Millerがよく言っているように、「大きなテストを行う前に小さなテストを行う」。
Dennis Doomen 2015年

6

内部クラスの場合は、単独で使用してはなりません。したがって、そのオブジェクトを内部で使用する他のクラスのテストとは別に、実際にそれをテストするべきではありません。

クラスのプライベートメンバーをテストしないように、DLLの内部クラスもテストしないでください。これらのクラスは、一般にアクセス可能ないくつかのクラスの実装の詳細であるため、他の単体テストを通じて十分に活用する必要があります。

内部実装の詳細をテストすると、テストが脆弱になるため、クラスの動作のみをテストしたいという考えです。すべてのテストを中断することなく、クラスの実装の詳細を変更できるはずです。

そのクラスを本当にテストする必要があるとわかった場合は、そもそもそのクラスが内部である理由を再検討する必要があるかもしれません。


2
実装の詳細は、包括的なテストの一部として実行する必要があります。プライベート変数をのぞかないでください...期待される動作をテストします。テストが正しい場合、すべての内部配管と配線をその一部としてテストする必要があります。投票した。
岐阜

69
私は、これらのクラスは、DLL内の他のクラスへの「パブリック」であり、クラスの機能をindepdentlyテストする必要があり、このに同意必ずしもいけない
leora

27
私も同意しません。ユニットはユニットであり、個別にテストする必要があります。
Sentinel

5
非常に一般的なガイドラインですが、独断的ではありません。テストは2つの主な目的を果たします。1)回帰-何かを壊していないことを確認します。2)開発の速度を上げます。コード行を記述したいたびに巨大なサービスに立ち向かわなければならない場合、開発が妨げられます。複雑な内部要素がある場合は、分離して開発およびテストできるようにしたいと考えています。逆に、すべてを分離してテストしたくない(したがって、回帰テストの値を減らしたり、テストコードを複製したりしたい)が、一部のコードは分離を正当化する。おそらく重要なのは、それを別のアセンブリにすることです。
Lee Jensen

2
ここのOPは正しいです。テストを内部実装に結合しています。したがって、あなたのチームはテストと恐ろしいモックコードを修正するための奴隷です。パッケージ化されたlib APIまたはネットワークに公開されたAPIであることを確認して、パブリックAPIのみをテストします。すべてのコードは、正面玄関から実行できる必要があります。テスト実装がTDDの大部分が機能しなくなった理由です。システムの動作を保証することに重点を置くのではなく、文字通りアプリ全体のすべてのクラスをテストするのは巨大なPITAです。「権威のある」本を含むほとんどすべての人が、これを間違っているか、明確にしていないと思います。
ルークプレット

4

文書化の目的で

または、Type.GetTypeメソッドを使用して内部クラスをインスタンス化できます

//IServiceWrapper is public class which is 
//the same assembly with the internal class 
var asm = typeof(IServiceWrapper).Assembly;
//Namespace.ServiceWrapper is internal
var type = asm.GetType("Namespace.ServiceWrapper");
return (IServiceWrapper<T>)Activator
    .CreateInstance(type, new object[1] { /*constructor parameter*/ });

ジェネリック型の場合、次のように異なるプロセスがあります。

var asm = typeof(IServiceWrapper).Assembly;
//note the name Namespace.ServiceWrapper`1
//this is for calling Namespace.ServiceWrapper<>
var type = asm.GetType("Namespace.ServiceWrapper`1");
var genType = type.MakeGenericType(new Type[1] { typeof(T) });
return (IServiceWrapper<T>)Activator
     .CreateInstance(genType, new object[1] { /*constructor parameter*/});

-5

クラスは公開と封印の両方が可能です。

しかし、それをしないでください。

内部クラスを反映するツールを作成し、リフレクションを介してすべてにアクセスする新しいクラスを生成できます。MSTestはそれを行います。

編集:つまり、元のアセンブリに-テスト-のものを含めたくない場合。これは、メンバーがプライベートの場合にも機能します。


1
待って、何?作ってはいけないと言ってるのpublic sealed class?その宝石のあなたの理由は何ですか?
クラッシュ

@crush traumaponyは2009
Falken教授
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.