かずきのBlog@hatena

すきな言語は C# + XAML の組み合わせ。Azure Functions も好き。最近は Go 言語勉強中。日本マイクロソフトで働いていますが、ここに書いていることは個人的なメモなので会社の公式見解ではありません。

Metro スタイルアプリケーションで実験コードを書くとき

GUIアプリケーションで実験コード書くのってちょっと苦痛じゃないですか?個人的には苦痛です。さらに、Metroスタイルアプリなので現在のCP版だと、いちいちインストールしたりエミュレータ起動させたりとちょっとお試しするのにもげんなりです。

単体テストしようぜ!

ということでどうするかというと単体テストやるのが個人的におすすめです。確かExpress版でも単体テスト機能サポートされると記憶しているのでがんがん使っていきましょう!

やり方

Windows Metro styleの下にある単体テストライブラリを選択します。そうすると単体テストクラスが1つ作られたプロジェクトができるので、そこにお試しコードを書いていきます。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace UnitTestProject1
{
    [TestClass]
    public class UnitTest1
    {
        [TestMethod]
        public void TestMethod1()
        {
            // ここにお試しコード書いてAssertする
            Assert.AreEqual("期待値", "実際の値");
        }
    }
}

これで単体テスト実行すればいいのですが、いちいち単体テストの実行を命令するのもめんどくさいというものぐさな人に素敵な機能が追加されています。メニューの「単体テスト」→「単体テスト設定」→「Run Tests After Build」をチェックしておきます。こうすると設定の名前の通りビルドするたびに単体テストが実行されます!!ショートカットC#開発の設定にしてる人は「F6」か「Ctrl + Shift + B」ですね。ビルドすると、単体テストエクスプローラに以下のように結果が表示されます。エミュレータとかでやるよりも個人的にはお手軽です。

ちなみにテスト成功すると青になります。

まとめ

ということで、Metro スタイルアプリで実験コードを書くときは単体テストをやったほうが捗りそうです。単体テストエクスプローラで即座に結果もわかるしエミュレータも起動しないし、ローカルにいらんアプリケーションがインストールされることもないです。
そして、出来ることなら本番アプリケーション作るときも単体テストプロジェクトを作っておいて書いたコードを即座に確認できるようにしておくといいと思います。

おまけ

ということでMEFがMetro スタイルアプリでも使えるというらしいということで色々試そうとしてたらCompositionContaienrクラスがない!どうなってるんだ!?といって色々試そうとしたときの単体テストコードが以下のような感じです。

namespace UnitTestProject1
{
    using System.ComponentModel.Composition;
    using System.ComponentModel.Composition.Hosting;
    using System.ComponentModel.Composition.Registration;
    using System.Reflection;
    using Microsoft.VisualStudio.TestTools.UnitTesting;

    [TestClass]
    public class UnitTest1
    {
        [Import]
        public GreeterClient Client { get; set; }

        [TestCleanup]
        public void TearDown()
        {
            this.Client = null;
        }

        [TestMethod]
        public void TestMethod1()
        {
            // MEF2では属性なしでもExport Importできる
            var builder = new RegistrationBuilder();
            builder
                .ForType<Greeter>()
                .Export();
            builder
                .ForType<GreeterClient>()
                .ImportProperty(
                    p => p.Greeter, 
                    config => config.AsContractType<Greeter>())
                .Export();

            var catalog = new AssemblyCatalog(
                typeof(UnitTest1).GetTypeInfo().Assembly,
                builder);
            // カタログからCompositionServiceというのを作るらしい
            var service = catalog.CreateCompositionService();

            // そしてImport
            Assert.IsNull(this.Client);
            service.SatisfyImportsOnce(this);
            Assert.IsNotNull(this.Client);

            // 結果確認
            Assert.AreEqual("Hello world Metro!!", this.Client.Execute());
        }
    }

    public class GreeterClient
    {
        public Greeter Greeter { get; set; }

        public string Execute()
        {
            return this.Greeter.Greet() + " Metro!!";
        }
    }

    public class Greeter
    {
        public string Greet()
        {
            return "Hello world";
        }
    }
}

コンテナなくなってしまうのかな・・・。