« [ブログ紹介] TFS 2010 で新しくなること | トップページ | [イベント] 告知 - "TDD" Boot Camp ( 12/19, 青山 ) »

2009年11月16日 (月)

[コラム] [Visual Studio] 抽象クラスの private メソッドを単体テストするには

※ 初出: biac の それさえもおそらくは幸せな日々@nifty, 2008年5月2日

Visual Studio では、 プライベートメソッドに対しても、 ユニットテストのスケルトンコードを自動生成してくれます。 プライベートメソッドを持つクラスに対するアクセッサークラスを、 自動的に作ってくれるわけです。 そして、 ユニットテスト側では、 この自動生成されたアクセッサークラスを使って、 テストを書きます。
それを踏まえて…

では、 テスト対象のメソッドが、 抽象クラスに含まれているときはどうすればいいでしょう?

こんなテスト対象のクラス AbstractClass1 があったとします。

namespace 抽象クラス {
    internal abstract class AbstractClass1 {
        protected int _num;
        internal AbstractClass1() {
            this._num = 1;
        }
        protected abstract bool foo(int n);
        private bool bar(int n) {
            return (this._num == n);
        }
    }
}

さて、 この private なメソッド bar() を、 Visual Studio 2008 のユニットテスト機能で、 直接テスト出来るでしょうか?

※ 通常は、 private メソッドを呼び出している protected 以上のメソッドが必ず存在しますから、 そこをテストすることで間接的に private メソッドをテストできます。 その手法では、 対象メソッドが複雑すぎてやってられない、 というとき、 private メソッドを直接テストしたくなるわけです。

まず、 いくらなんでも抽象クラスだけではインスタンス化できませんから、 どうしても実装クラスは必要です。 AbstractClass1 を継承したクラス ConcreteClass1 を、 ユニットテストのためだけに実装します。

namespace 抽象クラス {
#if UNIT_TEST
    internal class ConcreteClass1 : AbstractClass1 {
        protected override bool foo(int n) {
            return (base._num != n);
        }
    }
#endif
}

この ConcreteClass1 に対して、 単体テストウィザードでテストコードを自動生成させれば、 ConcreteClass1 の方に実装されている protected メソッド foo() はテストできます。

でも、 それで自動生成された ConcreteClass1_Accessor クラスを使って、 親クラスの private メソッド bar() をテストしようとしても、 出来ません。 ConcreteClass1 から、 継承元のプライベートメソッドは見えませんからね。

そこで、 こんな風にしてユニットテスト側で AbstractClass1 のアクセッサークラスを作ってやると、 bar() もテストできるようになります。

    [TestMethod()]
    [DeploymentItem("抽象クラス.dll")]
    public void barTest()
    {
        // 実装クラスのインスタンスから、
        // 抽象クラス (親) の Accessor を生成する。
        PrivateObject po = new PrivateObject(
            new ConcreteClass1(),
            new PrivateType(typeof(AbstractClass1))
            );
        AbstractClass1_Accessor target
            = new AbstractClass1_Accessor(po);

        // 親クラスの実装 private bar() をテスト
        Assert.IsFalse(target.bar(0));
        Assert.IsTrue(target.bar(1));

        // 子クラスの実装 protected foo() も見える
        Assert.IsTrue(target.foo(0));
        Assert.IsFalse(target.foo(1));
    }

|

« [ブログ紹介] TFS 2010 で新しくなること | トップページ | [イベント] 告知 - "TDD" Boot Camp ( 12/19, 青山 ) »

*コラム」カテゴリの記事

コメント

コメントを書く



(ウェブ上には掲載しません)




トラックバック


この記事へのトラックバック一覧です: [コラム] [Visual Studio] 抽象クラスの private メソッドを単体テストするには:

« [ブログ紹介] TFS 2010 で新しくなること | トップページ | [イベント] 告知 - "TDD" Boot Camp ( 12/19, 青山 ) »