NUnit を正しく使用する方法を考えています。最初に、メイン プロジェクトをリファレンスとして使用する別のテスト プロジェクトを作成しました。ただし、その場合、プライベート メソッドをテストすることはできません。私の推測では、テスト コードをメイン コードに含める必要があるのではないでしょうか?! - それは正しい方法ではないようです。(テストを含むコードを出荷するという考えは嫌いです。)
NUnit でプライベート メソッドをどのようにテストしますか?
NUnit を正しく使用する方法を考えています。最初に、メイン プロジェクトをリファレンスとして使用する別のテスト プロジェクトを作成しました。ただし、その場合、プライベート メソッドをテストすることはできません。私の推測では、テスト コードをメイン コードに含める必要があるのではないでしょうか?! - それは正しい方法ではないようです。(テストを含むコードを出荷するという考えは嫌いです。)
NUnit でプライベート メソッドをどのようにテストしますか?
一般に、単体テストは、結果がクライアントの観点から正しい限り、実装は重要ではないという理論に基づいて、クラスのパブリック インターフェイスに対処します。
そのため、NUnit は非パブリック メンバーをテストするためのメカニズムを提供しません。
単体テストの焦点がパブリック インターフェイスであることには同意しますが、プライベート メソッドもテストすると、コードの印象がはるかに細かくなります。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 クラスをモックするのに非常に役立ちます。
願わくば、この回答が、単体テスト全般に関する情報を提供し、単体テストからより良い結果を得るのに役立つ情報をもう少し提供してくれることを願っています。
私は、プライベート メソッドをテストする機能を持つことに賛成です。xUnit が開始されたときは、コードを記述した後に機能をテストすることを目的としていました。この目的には、インターフェースをテストするだけで十分です。
単体テストは、テスト駆動開発へと進化しました。すべてのメソッドをテストする機能があると、そのアプリケーションに役立ちます。
この質問はかなり進んでいますが、これを行う方法を共有したいと思いました。
基本的に、アセンブリの「デフォルト」の下にある「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
明らかに、開発中にこのメソッドを使用しないようにする必要がありますが、使用すると、リリース ビルドはすぐにこのメソッドへの不注意な呼び出しを示します。
単体テストの主な目的は、クラスのパブリック メソッドをテストすることです。これらのパブリック メソッドは、それらのプライベート メソッドを使用します。単体テストでは、公開されているものの動作をテストします。
これで質問に答えられない場合はお詫びしますが、リフレクション、#if #endif ステートメントを使用する、プライベート メソッドを表示するなどの解決策では問題は解決しません。プライベート メソッドを可視化しない理由はいくつか考えられます。たとえば、それが運用コードであり、チームがレトロスペクティブに単体テストを作成している場合はどうでしょうか。
私が取り組んでいるプロジェクトでは、(悲しいことに) MSTest だけが、アクセサーを使用してプライベート メソッドを単体テストする方法を持っているようです。
単体テストの理論では、コントラクトのみをテストする必要があります。つまり、クラスのパブリック メンバーのみです。しかし実際には、開発者は通常、内部メンバーもテストしたいと考えています。それは悪いことではありません。はい、理論に反しますが、実際には役立つ場合があります。
したがって、本当に内部メンバーをテストしたい場合は、次のいずれかの方法を使用できます。
コード例 (疑似コード):
public class SomeClass
{
protected int SomeMethod() {}
}
[TestFixture]
public class TestClass : SomeClass{
protected void SomeMethod2() {}
[Test]
public void SomeMethodTest() { SomeMethod2(); }
}
プライベート関数はテストしません。リフレクションを使用してプライベート メソッドとプロパティにアクセスする方法があります。しかし、それは簡単なことではありません。
公開されていないものはテストしないでください。
いくつかの内部メソッドとプロパティがある場合は、それを public に変更するか、アプリと共にテストを出荷することを検討する必要があります (実際には問題とは思わないものです)。
顧客がテスト スイートを実行して、提供したコードが実際に「機能している」ことを確認できた場合、これは問題ではないと思います (これによって IP を譲渡しない限り)。すべてのリリースに含めるものは、テスト レポートとコード カバレッジ レポートです。
クラスの非静的プライベート メソッドにアクセスする必要がある場合は、これを試すことができます。
class Foo
{
private int Sum(int num1, int num2)
{
return num1 + num2;
}
}
MethodInfo sumPrivate =
typeof(Foo).GetMethod("Sum", BindingFlags.NonPublic | BindingFlags.Instance);
int sum = (int)sumPrivate.Invoke(new Foo(), new object[] { 2, 5 });
// 7
プライベート メソッド パッケージが表示されるようにします。そうすれば、これらのメソッドをテストしながら、適度に非公開に保つことができます。公開インターフェースだけをテストする必要があるという人々の意見には同意しません。プライベート メソッドには、外部インターフェイスを経由するだけでは適切にテストできない非常に重要なコードが含まれていることがよくあります。
つまり、正しいコードや情報の隠蔽にもっと関心があるかどうかにかかっています。これらのメソッドにアクセスするには、誰かが自分のクラスをパッケージに配置する必要があるため、パッケージの可視性は良い妥協点だと思います。それが本当に賢いことなのかどうか、彼らはよく考え直さなければなりません。
私はJavaの男なので、パッケージの可視性はC#ではまったく異なるものと呼ばれる可能性があります。これらのメソッドにアクセスするために、2 つのクラスが同じ名前空間に存在する必要がある場合です。