web-dev-qa-db-ja.com

NUnitでプライベートメソッドをテストするにはどうすればよいですか?

NUnitを正しく使用する方法を知りたいです。最初に、メインプロジェクトを参照として使用する別のテストプロジェクトを作成しました。しかし、その場合、私はプライベートメソッドをテストすることはできません。私の推測では、テストコードをメインコードに含める必要がありましたか?! -それは正しい方法ではないようです。 (テストを含むコードを出荷するという考えは嫌いです。)

NUnitでプライベートメソッドをテストするにはどうすればよいですか?

99
MrFox

一般に、ユニットテストは、結果がクライアントの観点から正しい限り、実装が重要でないという理論に基づいて、クラスのパブリックインターフェイスに対処します。

そのため、NUnitは非公開メンバーをテストするメカニズムを提供していません。

73
harpo

ユニットテストの焦点はパブリックインターフェイスであることに同意しますが、プライベートメソッドもテストすると、コードの印象がはるかに細かくなります。 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を変更する必要があることに注意してください。上記の例は、インスタンスメソッドのみです。

50
user1039513

単体テストを記述する一般的なパターンは、パブリックメソッドのみをテストすることです。

テストするプライベートメソッドが多数あることがわかった場合、通常、これはコードをリファクタリングする必要があることを示しています。

これらが現在存在するクラスでこれらのメソッドをパブリックにするのは間違っています。それはあなたがそのクラスに持たせたい契約を破ります。

それらをヘルパークラスに移動し、そこで公開するのが正しい場合があります。このクラスは、APIによって公開されない場合があります。

この方法では、テストコードがパブリックコードと混ざることはありません。

同様の問題は、プライベートクラスのテストです。アセンブリからエクスポートしないクラス。この場合、InternalsVisibleTo属性を使用して、テストコードアセンブリを製品コードアセンブリのフレンドに明示的に設定できます。

46
morechilli

テストアセンブリを、テストするターゲットアセンブリのフレンドアセンブリとして宣言することにより、プライベートメソッドをテストすることができます。詳細については、以下のリンクを参照してください。

http://msdn.Microsoft.com/en-us/library/0tke9fxk.aspx

これは、テストコードと運用コードをほとんど分離するので便利です。私はこの方法の必要性を発見したことがないので、自分でこの方法を使ったことはありません。私はあなたのコードをどのように処理するかを見るためにあなたのテスト環境で単に複製できない極端なテストケースを試してテストするためにそれを使用できると思います。

ただし、既に述べたように、プライベートメソッドをテストする必要はありません。 likley以上に、コードをより小さなビルディングブロックにリファクタリングする必要があります。リファクタリングを行う際に役立つヒントの1つは、システムが関連するドメインを試して考え、このドメインに生息する「実際の」オブジェクトについて考えることです。システム内のオブジェクト/クラスは、実際のオブジェクトに直接関連付ける必要があります。これにより、オブジェクトに含まれる正確な動作を分離し、オブジェクトの責任を制限することができます。これは、特定のメソッドをテストできるようにするためだけでなく、論理的にリファクタリングしていることを意味します。オブジェクトの動作をテストできます。

内部でテストする必要性をまだ感じている場合は、1つのコードに焦点を合わせたいと思うので、テストでモックを検討することもできます。モックとは、オブジェクトの依存関係をインジェクトするものですが、インジェクトされるオブジェクトは「実際の」オブジェクトや実動オブジェクトではありません。これらは、動作エラーを簡単に分離できるように、動作がハードコードされたダミーオブジェクトです。 Rhino.Mocksは人気のある無料のモックフレームワークであり、基本的にオブジェクトを作成します。 TypeMock.NET(コミュニティエディションが利用可能な商用製品)は、CLRオブジェクトをモックできるより強力なフレームワークです。データベースアプリのテスト時に、たとえばSqlConnection/SqlCommandクラスとDatatableクラスをモックするのに非常に便利です。

この回答により、ユニットテスト全般についての情報が得られ、ユニットテストの結果が改善されることを願っています。

20
Dafydd Giddins

私はプライベートメソッドをテストする機能を持っていることに賛成です。 xUnitは、コードの作成後に機能をテストするためのものでした。この目的には、インターフェースのテストで十分です。

単体テストはテスト駆動開発に進化しました。すべてのメソッドをテストする機能があると、そのアプリケーションに役立ちます。

6
Mark Glass

単体テストの主な目標は、クラスのパブリックメソッドをテストすることです。これらのパブリックメソッドは、プライベートメソッドを使用します。単体テストでは、公開されているものの動作をテストします。

4
Maxime Rouiller

この質問は高度な年にありますが、私はこれを行う方法を共有すると思いました。

基本的に、アセンブリのすべての単体テストクラスは、そのアセンブリの「デフォルト」の下の「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

明らかに、開発中にこのメソッドを使用しないことを確認する必要がありますが、リリースビルドでは、このメソッドを誤って呼び出したことがすぐに示されます。

4
Stuart Wood

これで問題が解決しない場合はおologiesびしますが、リフレクションを使用する、#if #endifステートメントを使用する、プライベートメソッドを表示するなどの解決策では問題は解決しません。プライベートメソッドが表示されない理由はいくつかあります。実稼働コードであり、チームが単体テストを遡及的に記述している場合はどうでしょうか。

私がMSTestのみで作業しているプロジェクトでは(残念ながら)アクセサを使用してプライベートメソッドを単体テストする方法があるようです。

3
Ritesh

プライベート関数をテストしません。リフレクションを使用して、プライベートメソッドとプロパティを取得する方法があります。しかし、それは本当に簡単なことではなく、私はこの慣習を強く勧めています。

単に公開されていないものをテストするべきではありません。

内部メソッドとプロパティがいくつかある場合は、それをパブリックに変更するか、テストをアプリに同梱することを検討する必要があります(実際には問題とは思われません)。

顧客がテストスイートを実行して、配信したコードが実際に「機能している」ことを確認できる場合、これを問題とは見なしません(これによってIPを提供しない限り)。すべてのリリースに含まれるのは、テストレポートとコードカバレッジレポートです。

2
Tigraine

単体テストの理論では、契約のみをテストする必要があります。つまり、クラスの公開メンバーのみです。しかし実際には、開発者は通常、内部メンバーをテストしたいと考えています。 -そして、それは悪くありません。はい、それは理論に反しますが、実際には時々役立つことがあります。

したがって、内部メンバーを本当にテストしたい場合は、次のいずれかのアプローチを使用できます。

  1. メンバーを公開します。多くの本では、著者はこのアプローチを単純なものとして提案しています
  2. メンバーを内部にし、 InternalVisibleTo をasseblyに追加できます
  3. クラスメンバーを保護し、テスト中のクラスからテストクラスを継承できます。

コード例(擬似コード):

public class SomeClass
{
    protected int SomeMethod() {}
}
[TestFixture]
public class TestClass : SomeClass{

    protected void SomeMethod2() {}
    [Test]
    public void SomeMethodTest() { SomeMethod2(); }
}
1
burzhuy

メソッドを内部で保護し、Assembly: InternalVisibleTo("NAMESPACE")をテスト名前空間に使用できます。

したがって、NO!プライベートメソッドにアクセスすることはできませんが、これは回避策です。

1
Furgalicious

プライベートメソッドパッケージを表示します。そうすれば、それらのメソッドをテストしながら、合理的にプライベートに保つことができます。パブリックインターフェイスだけをテストする必要があると言っている人々には同意しません。プライベートメソッドには、外部インターフェイスを経由するだけでは適切にテストできない非常に重要なコードがしばしばあります。

ですから、正しいコードや情報の隠蔽をもっと気にするなら、それは本当に要約されます。これらのメソッドにアクセスするには、パッケージにクラスを配置する必要があるため、パッケージの可視性は良い妥協案だと思います。それは彼らにそれが本当に賢いことであるかどうかについて本当に考えさせるべきです。

私はJava guy btwであるため、パッケージvisibliltyはC#ではまったく異なるものと呼ばれる場合があります。これらのメソッドにアクセスするために2つのクラスが同じ名前空間になければならないときです。

0
Fylke