読者です 読者をやめる 読者になる 読者になる

亀岡的プログラマ日記

京都のベッドタウン、亀岡よりだらだらとお送りいたします。

JUnit実践入門 MSTest用パッチ #TddAdventJp

C# TDD

GUIテストについて書くといったな。あれは嘘だ』(C.V 玄田 哲章)

というわけで、TDDアドベントカレンダー13日目です。タイトル通り、MSTestの話をします。

昨日はTugu Katagiriさんの【TDD Advent Celndar 2012】12日目:虫退治もTDD!+オマケ話でした。バグをテストを書いて立ち向かう、というのはTDDの取っ掛かりとしてもいいですよね。和田さんもきのこ本で書いておられましたし。

なぜMSTest?

TDD界隈では、結構な数のC#用のチュートリアルがあります。しかし、MSTestは意外に取り扱われることが少ないです。実際2010までは実質Pro以上の有償版専用でしたし、なかなか初心者用のチュートリアルとして組むのもためらわれるのがあったのかと思います。やはり主流派NUnitという感があります。*1
しかしVS2012からTestExplolerがExpress版にも導入され、MSTestに限ってはテストランナーの統合がExpressから可能になりました。もちろん、SharpDevelopMonoDevelopを使えばIDEと統合されたTest環境を手に入れることはできますが、C#の言語機能を生かし切るには、やはりVisualStudioというパワフルなツールと親しんでおくことも必要かな、とも思うのです。(Pro版を入れるとResharperはじめ恐ろしく高機能なサポートツールを使うことができるようにもなりますし)。こんな事言うと怒られそうなんですが、単体テストデバッグ実行も非常に簡単になりますし、やはり統合環境へと統合するのは自然なことだと思います。

しかし残念ながらMSTestは結構機能的に弱い部分もあるフレームワークでもあります。というわけで、VS Expressでの導入からちょっとでも便利に使うためのTipsなどをまとめておきたいと思います。


あ、言語はC#で書きますが、VB.netでも大して変わらないはず・・・。

VS Express での書き方

まずはJUnit実践入門でのチュートリアルに当たる所をさらっと触れておきましょう。IDEにバンドルされていますのでインストールは不要です。

ソリューションの新規作成

ここは通常通りです。普通に作成しましょう。プロジェクト名は適当に。
f:id:posaunehm:20121213232058p:plain

テストプロジェクトの作成

次にテストプロジェクトです。ExpressEditionからちゃんとテストプロジェクトを選択できます。
f:id:posaunehm:20121213232259p:plain

テストクラス・テストメソッドの作成

デフォルトはこんな感じです。2010以前のごちゃごちゃしたテンプレートと比べると格段にマシですね。これは良い進化だと思います。(進化でもないけれど)

using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace Test
{
    [TestClass]
    public class UnitTest1
    {
        [TestMethod]
        public void TestMethod1()
        {
        }
    }
}

テストクラスにTestClass属性、テストメソッドにTestMethod属性がついていますね。

とりあえずデフォルトのファイル名は良くないので適当に変えちゃいましょう。Junit実践入門に沿うならCalculatorTestですかね。ちなみにVisualStudioではファイル名とクラス名が一致している場合には、ファイル名を変えるとクラス名も自動で変えてくれますよ。

f:id:posaunehm:20121213233021p:plain

IDEの自動補完でガンガン作って行きたいので、まず先にテストメソッドを作っちゃいましょう。

using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace Test
{
    [TestClass]
    public class CalculatorTest
    {
        [TestMethod]
        public void 足し算のテスト_1と1を加算すると2になる()
        {
            var sut = new Calculator();

            var result = sut.Addition(1, 1);
            Assert.Equals(result, 2);
        }
    }
}

当然ここでコンパイルは通らないのですが、慌てず騒がず、「Ctrl + . 」と押しますと。

f:id:posaunehm:20121213233859p:plain
こうなって。

f:id:posaunehm:20121213234030p:plain
ここで色々選んでクラスを作ります。

今度はAdditionメソッドがエラーになりますので慌てず騒がず、「Ctrl + .」と押して
f:id:posaunehm:20121213234320p:plain

とまぁ1文字もタイプせずに雛形はこんな感じで出来ます。VSでは基本シーケンスとしてまず先にテストを書いたほうがノリヤスイ気がしてます。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace CalculatorConsole
{
    public class Calculator
    {
        public object Addition(int p1, int p2)
        {
            throw new NotImplementedException();
        }
    }
}

後は実装するだけですね!


この辺りのもっと実践的な話は@masaru_b_clさんのTDDにIDEを活用しようが動画付きで非常に分かりやすいです。CodeRushなどは有償VSでしか使えない拡張機能ですが、Ctrl+.やリネームなどはある程度Express Editionで動作しますので大いに参考にして下さい。*2

使用可能な属性について

JUnitと大きく違うのはテストクラス自体に属性が必要なところでしょうか。それ以外のクラス単位の属性はだいたい等価なものがあります。以下にまとめてみると・・・

JUnit MSTest
@Test TestMethod
@Ignore Ignore
@Before TestInitialize
@After TestCleanup
@BeforeClass ClassInitiaize
@AfterClass ClassCleanup

とりあえずこれだけあれば困りはしないでしょう。

テストの管理

2012/12/14追記

VS2012のアップデートに伴い、改善されていました。情報が古くて申し訳ありませんです。。。
詳しくは以下へ。

テストは管理できます。んが。

テストの管理はNamespaceやClass単位で「コンテキスト」というものが暗黙的に与えられますのでそれをうまく使います。「Ctrl + R, T」で現在カーソルがあるコンテキストのテストを全て実行する、というコマンドがありますので適切な位置で実行するとある程度管理できます。・・・ってやめて!石投げないで!!

もう一つ方法があります。TestCategory属性を使う方法です、例えばテストにこんなカテゴリを付けられます。

[TestMethod]
[TestCategory("SlowTest")]
public void 足し算のテスト_1と1を加算すると2になる()
{
    var sut = new Calculator();

    var result = sut.Addition(1, 1);
    Assert.Equals(result, 2);
}

*3

そしてこれは!MSTest.exeのコマンドラインオプションで呼び分けられます!!

mstest /testcontainer:Test.dll /category:SlowTest

ああやめてグーはやめてください痛い痛い!

IDE統合されないカテゴリ分け

Visual Studio 2012では残念ながらテストのカテゴリ分けが非常にショボくなってしまいました。2010以前はかなり細かく設定できたのですが・・・。これはかなりブーイングされているようでして、Issuesにもあがっています。

サポートライブラリの使用

とりあえずこれで導入まではさっくりいけたでしょうか。それでは次にどんどんテストを書いていくにあたっての機能不足を補う便利なライブラリを入れておきましょう。

その前に、Nugetの紹介です。

Nugetで気軽にパッケージ管理しましょう。

Nugetは要するにJavaでいうところのMavenでのパッケージ管理を.NETで行うツールです。プロジェクトごとに使用するパッケージを管理してくれます。(基本的にはInstallとUninstallとアップデートしか使わないのですが)

NugetもExpress Editionに最近登場しましたので、シンプルに拡張機能を手に入れつことができます。
プロジェクトを右クリックしてNugetパッケージの管理、というのを選択するとGUIでの管理もできます。

f:id:posaunehm:20121214002038p:plain

なにか面白いライブラリ無いかなー、という時にはGUIの方が便利なのですがそうでない時にはコンソールから入れるのがシンプルでいいです。コンソールは『表示→その他のウィンドウ→パッケージマネージャーコンソール』*4とたどってください。

Chaining Assertionの導入

それではまず第一歩というところで、MSTestの弱点をほぼ一つでカバーしてくれる@neucc先生作のChaining Assertionを導入しましょう。
パッケージマネージャーコンソールで以下のようにタイプすると降ってきます。第3引数はセットするプロジェクト名です。今回はTestプロジェクトに追加していますね。

PM> Install-Package ChainingAssertion Test

Chaining Asserionでできることは色々あるのですが、大きくはMatcher系のAPIの強化とTestCase導入です。

Matcher APIの強化

MatcherAPIとはAssert系での検証を行うAPI群です。特にAssertThat系の書き方はなかなか特徴的ですよね。NUnitもAssertThat構文を持っていますし。

    //NUnit
    Assert.That(actual, Is.EqualTo(expected);

こういった読みやすい形のAssertionを提供してくれるのがChaining Assertionです。例えば先ほどの足し算の和を求めるコードだと以下のように書きます。

    var sut = new Calculator();
    var result = sut.Addition(1, 1);
    result.Is(2);

ここまでスッキリかけるともうこう書きたくなりますね。

    var sut = new Calculator();
    sut.Addition(1, 1).Is(2);

これだけでなく、CollectionのAssertを使いやすくラップしていてくれていたり、比較用の関数をラムダで与えられたりと、かなりの多機能ですので一度チェックしてみてください。

TestCaseを使う

ちなみに、Chaining Assertionを使うとTestCaseも(擬似的に)実現できます。準備としては

  1. publicのTestContextプロパティを作っておく
  2. TestCase属性を用いてテストケースを書いておく。
  3. メソッド内部でTestContextからテストケース分の引数を渡すようなデリゲート(普通はラムダ式)を差し込んでおく。

こんな感じになりますね。

    [TestMethod]
    [TestCase(1, 1, 2)]
    [TestCase(1, 2, 3)]
    [TestCase(1, 3, 4)]
    [TestCase(2, 3, 5)]
    [TestCase(2, 4, 6)]
    public void 足し算のテスト()
    {
        TestContext.Run((int pl, int pr, int result) =>
        {
            var sut = new Calculator();
            sut.Addition(pl, pr).Is(result);
        });
    }

他にも例外送出テストとか、プロパティを渡すタイプのTestCaseの書き方とか、DynamicAccessとか、ありますので、是非ホームページで色々勉強しましょう。

Mockライブラリの使用

最後にMockライブラリについて触れておきましょう。現状二大巨頭として立つのがRhino MockMoqです。この2つは使い勝手的にもそこまで大差がなく、本で紹介されているMochitoとほぼ同様の挙動をしてくれます。Moqに関しては別記事でまとめるかも。

終わりに

ざくっとVS Expressでテストをする際の注意点等を説明させてもらいましたが、そこまで難しくないと思われたんじゃないでしょうか。私もExpressで触ってみて、もっと苦戦するかと思いましたが割りと簡単にテストコードの実行まで辿りつけました。中規模くらいまでは十分にExpressで作成していくことも可能でしょう。

VS Expressをもっといっぱい使ってみましょう!

*1:私は[http://xunit.codeplex.com/:title=xUnit.net]派です。

*2:もちろん製品版使っている人は各種拡張ツールも込で要チェック!

*3:SlowTestなわけねーだろ!、というツッコミはさておいてですね・・・

*4:深くにありすぎて本当に使ってもらう気があるのか疑わしいレベル