web-dev-qa-db-ja.com

コードを内部にするが、他のプロジェクトからの単体テストに使用可能にする

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

119
leora

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

関係するアセンブリを緊密に結合するため、これは慎重に使用する必要があります。 InternalsVisibleToの一般的な使用法は、単体テストプロジェクトです。上記の理由により、実際のアプリケーションアセンブリでの使用にはおそらく適切な選択ではありません。

例:

[Assembly: InternalsVisibleTo("NameAssemblyYouWantToPermitAccess")]
namespace NameOfYourNameSpace
{
188
Ash

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

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

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

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

6
Josh

文書化のため

または、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*/});
3
ktutnik