MSTest を使って RSpec っぽくテストを書いてみた

プライベートで RSpec 使ってテストを書いていると、 仕事でも RSpec っぽくテストを書きたくなる。 でも、仕事で使っている言語は C# だから、Visual Studio単体テスト機能(MSTest) しか使わせてもらえない。

RSpec は describe や context を入れ子に出来るから、 状態によって振る舞いの変わる機能のスペックが書きやすいんだよな。 C# で BDD やるためのフレームワークもあるにはあるけど、 オープンソースソフトウェアの導入許可って滅多に降りない。

なかなか諦め切れなくて、MSTest でなんとか RSpec っぽく書けないか試行錯誤していたら閃いた。 テストクラスを入れ子にすることで、MSTest でも RSpec っぽく書けるかも? 試しに MSTest で無理やり List のスペックを書いてみた。

[TestClass]
public class ListSpec
{
    protected List<int> _subject;

    [TestInitialize]
    public virtual void BeforeEach()
    {
        _subject = new List<int>();
    }

    [TestClass]
    public class CountSpec : ListSpec
    {
        [TestClass]
        public class 空のとき : CountSpec
        {
            [TestMethod]
            public void Countは0を返す()
            {
                Assert.AreEqual(0, _subject.Count);
            }
        }

        [TestClass]
        public class データを1件持っているとき : CountSpec
        {
            [TestInitialize]
            public override void BeforeEach()
            {
                base.BeforeEach();

                _subject.Add(1);
            }

            [TestMethod]
            public void Countは1を返す()
            {
                Assert.AreEqual(1, _subject.Count);
            }
        }
    }
}

入れ子にするとき、中のクラスが外のクラスを継承するのがポイント。 これで TestInitialize や TestCleanup が RSpec の before, after っぽく動いた。 ただ、外側のテストクラスを継承しているから、一斉にテストを走らせたとき、何度も同じテストが実行されてしまう。 テストメソッドを末端のテストクラスに書くように徹底すれば回避できるけど。

あと、Visual Studio 2012 なら、ソリューションエクスプローラーでスペックを見れるのはうれしい誤算だった。

f:id:griefworker:20130510211206p:plain

まぁ、NSpec や SpecFlow を使えるなら、最初からそれ使うのが一番いいんだけどね。