回答:
一般に、ユニットテストは、クライアントの観点から結果が正しい限り、実装は重要ではないという理論に基づいて、クラスのパブリックインターフェイスに対処します。
そのため、NUnitは非公開メンバーをテストするためのメカニズムを提供していません。
System.Reflection
バインディングフラグを使用して非パブリックメソッドにアクセスして呼び出すことができるため、NUnitをハックしたり、独自のフレームワークを設定したりできます。または(もっと簡単だと思います)、コンパイル時フラグ(#if TESTING)を設定してアクセス修飾子を変更し、既存のフレームワークを使用できるようにすることもできます。
単体テストの焦点はパブリックインターフェイスであることには同意しますが、プライベートメソッドもテストすると、コードの印象がはるかに細かくなります。MSテストフレームワークでは、PrivateObjectおよびPrivateTypeを使用してこれを可能にしますが、NUnitではできません。私が代わりに行うことは:
private MethodInfo GetMethod(string methodName)
{
if (string.IsNullOrWhiteSpace(methodName))
Assert.Fail("methodName cannot be null or whitespace");
var method = this.objectUnderTest.GetType()
.GetMethod(methodName, BindingFlags.NonPublic | BindingFlags.Instance);
if (method == null)
Assert.Fail(string.Format("{0} method not found", methodName));
return method;
}
この方法は、テスト性を優先してカプセル化を妥協する必要がないことを意味します。プライベート静的メソッドをテストする場合は、BindingFlagsを変更する必要があることに注意してください。上記の例は、単なるインスタンスメソッドです。
単体テストを記述する一般的なパターンは、パブリックメソッドのみをテストすることです。
テストしたいプライベートメソッドがたくさんある場合は、通常、これはコードをリファクタリングする必要のある兆候です。
これらのメソッドを、現在住んでいるクラスで公開するのは誤りです。それはあなたがそのクラスに持たせたい契約を破るでしょう。
それらをヘルパークラスに移動し、そこで公開するのが正しい場合があります。このクラスは、APIによって公開されない場合があります。
このようにして、テストコードがパブリックコードと混合されることはありません。
同様の問題は、プライベートクラスのテストです。アセンブリからエクスポートしないクラス。この場合、InternalsVisibleTo属性を使用して、テストコードアセンブリを製品コードアセンブリのフレンドにすることができます。
テストアセンブリを、テストするターゲットアセンブリのフレンドアセンブリとして宣言することにより、プライベートメソッドをテストすることができます。詳細については、以下のリンクを参照してください。
http://msdn.microsoft.com/en-us/library/0tke9fxk.aspx
これは、テストコードと本番コードをほとんど分離するので便利です。私はこの方法の必要性を見つけたことがないので、自分でこの方法を使用したことはありません。コードを使用してコードを処理する方法を確認するために、テスト環境で単純に複製できない極端なテストケースを試し、テストするためにそれを使用できると思います。
ただし、既に述べたように、プライベートメソッドをテストする必要はありません。リクリー以上に、コードを小さな構成要素にリファクタリングしたいと考えています。リファクタリングを行うときに役立つヒントの1つは、システムが関連するドメインについて考え、このドメインに存在する「実際の」オブジェクトについて考えることです。システム内のオブジェクト/クラスは、実際のオブジェクトに直接関連付ける必要があります。これにより、オブジェクトに含まれるべき正確な動作を分離し、オブジェクトの責任を制限することができます。これは、特定のメソッドをテストできるようにするだけでなく、論理的にリファクタリングしていることを意味します。オブジェクトの動作をテストできます。
それでも内部テストの必要性を感じている場合は、1つのコードに集中したいので、テストのモックを検討することもできます。モックとは、オブジェクトの依存関係をそこに注入するところですが、注入されたオブジェクトは「実際の」オブジェクトでもプロダクションオブジェクトでもありません。これらは、動作エラーを簡単に分離できるようにハードコードされた動作を持つダミーオブジェクトです。Rhino.Mocksは、基本的にオブジェクトを作成する人気のある無料のモックフレームワークです。TypeMock.NET(コミュニティエディションが利用可能な市販製品)は、CLRオブジェクトをモックできるより強力なフレームワークです。たとえば、データベースアプリのテスト時にSqlConnection / SqlCommandクラスとDatatableクラスをモックする場合に非常に役立ちます。
うまくいけば、この回答が一般的な単体テストについての情報を提供し、単体テストからより良い結果を得るのに役立つことを願っています。
この質問はその発展年にありますが、私はこれを行う方法を共有したいと思いました。
基本的に、私はすべての単体テストクラスを、そのアセンブリの「デフォルト」の下にある「UnitTest」名前空間でテストしているアセンブリに入れます。各テストファイルは次のようにラップされます。
#if DEBUG
...test code...
#endif
ブロックとは、a)リリースで配布されていないこと、b)フープジャンプなしでinternal
/ Friend
レベルの宣言を使用できることを意味します。
これが提供するもう1つのことは、この質問にさらに関連して、partial
プライベートメソッドをテストするためのプロキシを作成するために使用できるクラスの使用です。たとえば、整数値を返すプライベートメソッドのようなものをテストします。
public partial class TheClassBeingTested
{
private int TheMethodToBeTested() { return -1; }
}
アセンブリのメインクラスとテストクラス:
#if DEBUG
using NUnit.Framework;
public partial class TheClassBeingTested
{
internal int NUnit_TheMethodToBeTested()
{
return TheMethodToBeTested();
}
}
[TestFixture]
public class ClassTests
{
[Test]
public void TestMethod()
{
var tc = new TheClassBeingTested();
Assert.That(tc.NUnit_TheMethodToBeTested(), Is.EqualTo(-1));
}
}
#endif
明らかに、開発中にこのメソッドを使用しないことを確認する必要がありますが、Releaseビルドは、そうした場合、すぐに不注意な呼び出しを示します。
プライベート関数はテストしません。リフレクションを使用してプライベートメソッドとプロパティに入る方法があります。しかし、それは本当に簡単ではなく、私はこの習慣を強くお勧めしません。
公開されていないものはテストしないでください。
内部メソッドとプロパティがある場合は、それをパブリックに変更するか、テストをアプリに同梱することを検討する必要があります(私が実際に問題として認識していないもの)。
顧客がテストスイートを実行して、提供したコードが実際に「機能している」ことを確認できれば、これは問題ではありません(これによってIPを提供しない限り)。すべてのリリースに含めるものは、テストレポートとコードカバレッジレポートです。
ユニットテストの理論では、契約のみをテストする必要があります。つまり、クラスのパブリックメンバーのみです。しかし実際には、開発者は通常、内部メンバーをテストしたいと考えています。-そして、それは悪くありません。はい、それは理論に反しますが、実際にはそれは時々役立つことがあります。
したがって、内部メンバーを実際にテストする場合は、次のいずれかの方法を使用できます。
コード例(疑似コード):
public class SomeClass
{
protected int SomeMethod() {}
}
[TestFixture]
public class TestClass : SomeClass{
protected void SomeMethod2() {}
[Test]
public void SomeMethodTest() { SomeMethod2(); }
}
Message: Method is not public
。
プライベートメソッドパッケージを表示します。そうすれば、これらのメソッドをテストしながら、それを適度にプライベートに保つことができます。テストする必要があるのはパブリックインターフェイスだけであるという人々の意見には同意しません。多くの場合、プライベートメソッドには非常に重要なコードがあり、外部インターフェイスを経由するだけでは適切にテストできません。
ですから、正しいコードや情報の隠蔽についてもっと気にかけるかどうかということは、実際には結局のところです。これらのメソッドにアクセスするには、誰かが自分のクラスをパッケージに配置する必要があるため、パッケージの可視性は良い妥協だと思います。それは本当にそれが本当に賢いことかどうかを二度考えさせるでしょう。
ちなみに私はJavaの男なので、visibliltyパッケージはC#ではまったく別のものと呼ばれるかもしれません。これらのメソッドにアクセスするために、2つのクラスが同じ名前空間にある必要がある場合です。