1.21 jigowatts

Great Scott!

VSTest.Console でコマンドラインからテストを実行する

概要

前回MSBuildコマンドラインからビルドしてみました。ということで今回は単体テストコマンドラインから実行してみます。

sh-yoshida.hatenablog.com

f:id:sh_yoshida:20170528235357p:plain

環境

VSTest.Console

Visual Studioで書いた単体テストのコードをコマンドラインから実行するにはVSTest.Console.exeを使います。テストフレームワークの名前はMSTestだけどMSTest.exeじゃないってのはちと紛らわしいですね。

VSTest.Console.exe を使用して、単体テストまたはコード化された UI テストをコマンドラインから実行します。 これは Visual Studio 2012 以降のバージョンに関してパフォーマンスで最適化されており、MSTest.exe の代わりに使用されます。

https://msdn.microsoft.com/ja-jp/library/jj155800.aspx

Visual Studio Community 2017をデフォルトでインストールした場合のVSTest.Console.exeの場所は以下にありました。

C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\Common7\IDE\CommonExtensions\Microsoft\TestWindow\vstest.console.exe

構文

Vstest.console.exe [TestFileNames] [Options]

パスを通すか、フルパスでVSTest.Consoleを実行します。引数にはテスト対象のdll。長くなるので以降はパスは省略します。

> "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\Common7\IDE\CommonExtensions\Microsoft\TestWindow\vstest.console.exe" "C:\src\workspace\ClassLibrary1\ClassLibrary1Tests\bin\Debug\ClassLibrary1Tests.dll"

詳細なオプションは以下。
VSTest.Console.exe のコマンド ライン オプション

x64ビルドしたdllをテスト

64bitでビルドした場合、例えば"C:\src\workspace\ClassLibrary1\ClassLibrary1Tests\bin\x64\Debug"のようにテストプロジェクトのx64フォルダ以下にテストdllが出力されるので、こいつを引数に渡します。

> MSBuild ClassLibrary1.sln /t:clean;rebuild /p:configuration=Debug;platform=x64
> vstest.console ClassLibrary1Tests.dll /platform:x64 /framework:framework45 /inIsolation

複数のプロジェクトをテスト

それぞれのテスト対象dllのパスをスペースで区切って渡します。

> vstest.console ClassLibrary1Tests.dll ClassLibrary2Tests.dll

指定したテストメソッドのテスト

複数テストメソッドを指定する場合はカンマで区切って指定します。

> vstest.console ClassLibrary1Tests.dll /Tests:TestMethod1,TestMethod2

テスト結果ファイル(TRX)を出力

TestResultsフォルダに拡張子trxファイルが出力されます。このファイルをダブルクリックで開くとVisual Studioのテスト結果ウィンドウで見ることができます。

> vstest.console ClassLibrary1Tests.dll /Logger:trx

コードカバレッジを取得

Communityエディションでは残念ながら「警告: 診断データ アダプター ('コード カバレッジ') のメッセージ: CodeCoverage.exe が見つかりません。。」と表示され利用できません。

> vstest.console ClassLibrary1Tests.dll /EnableCodeCoverage

テスト実行

64bitでビルドして出来上がった二つのテストプロジェクトをテストして結果を出力してみました。

f:id:sh_yoshida:20170528235357p:plain

出力されたテスト結果ファイルをダブルクリック。

f:id:sh_yoshida:20170528235435p:plain

Visual Studioが起動して、テスト結果ウィンドウに表示されました。

f:id:sh_yoshida:20170529000736p:plain

コマンドラインでのビルドとテスト実行の雰囲気がなんとなくわかったところで次回はJenkinsと連携してみます!

MSBuildでコマンドラインからビルドする

概要

いつもVisual Studioからビルドしてましたが、コマンドラインMSBuild.exeを使ってビルドしてみます。あっ、今年はde:code行けなかったで(´;ω;`)スンスン

f:id:sh_yoshida:20170527011041p:plain

環境

MSBuild

Visual Studio Community 2017をデフォルトでインストールしたらexeは以下にありました。

C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\MSBuild\15.0\Bin\MSBuild.exe

構文

MSBuild.exe [Switches] [ProjectFile]  

パスを通すか、フルパスでMSBuildを実行。引数にはビルドするソリューションでok。

> MSBuild C:\src\workspace\ClassLibrary1\ClassLibrary1.sln

詳細なオプションは以下。オプションじゃなくてスイッチか。
MSBuild Command-Line Reference

いくつか頻繁に使いそうなスイッチをつけて実行してみるぞぃ。
長くなるのでパスは省略します。

ソリューションをクリーンしてリビルド

/target(/t)スイッチにターゲットを指定します。いつもVisualStudioでやってるやつや。

> MSBuild ClassLibrary1.sln /t:clean;rebuild 

64bit Debugビルド

/property:(/p)スイッチにConfigurationとPlatformを指定します。Releaseやx86を渡したりするんですね。

> MSBuild ClassLibrary1.sln /t:build /p:Configuration=Debug;Platform="x64"

Microsoftのすべての規則」でコード分析

/property:(/p)スイッチにRunCodeAnalysisとCodeAnalysisRuleSetを指定します。ルールセットにファイルのパスを渡すとクソ長くなりますのでよろしくお願いします。

> MSBuild ClassLibrary1.sln /t:build /p:RunCodeAnalysis=true;CodeAnalysisRuleSet="C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\Team Tools\Static Analysis Tools\Rule Sets\AllRules.ruleset"

ビルドログをファイルに出力

/verbosity:(/v)スイッチにdiagnostic(diag)を指定すると詳細なログがもりもり吐かれます。
/fileLogger(/fl)スイッチはカレントにmsbuild.logという名前でビルドログを出力してくれるやつ。かわいい。

> MSBuild ClassLibrary1.sln /t:build /v:diag /fl


これらを踏まえてスイッチをマシマシで流してみましょう。

メニュー
  • クリーン、リビルド
  • Debug
  • AnyCPU
  • コード分析(Microsoft マネージ推奨規則)
  • ビルドログの情報量(minimal)
  • ビルドログをファイル出力

f:id:sh_yoshida:20170527011041p:plain

うん、ログもちゃんと出ていますね。

f:id:sh_yoshida:20170527001947p:plain

(ふぅ、5月分の更新できた!)
次回はコマンドラインからMSTestでテストを実行する回の予定ですぅ。

ASP.NET MVCはじめました~データのキャッシュ

概要

データキャッシュの実装とテストについて調べてみました。

参考資料

ASP.NET MVCでのキャッシュについては、今のところ、キャッシュ機能をアプリケーションに注入する方法が推奨されています。

特定のキャッシュ機能の実装に依存しないようにキャッシュサービスを注入してあげれば良さそう。

環境

キャッシュサービスの実装

インターフェイスと実装。インターフェイスは必要に応じて機能を追加します。書籍のサンプルコードではSystem.Web.CachingのCacheオブジェクトを使用していましたが、System.Runtime.CachingのMemoryCacheオブジェクトに置き換えてみました。
/Framework/ICacheService.cs

public interface ICacheService
{
    Object Get(String key);
    void Set(String key, Object data);
    Object this[String key] { get; set; }
}

/Framework/AspNetCacheService.cs

public class AspNetCacheService : ICacheService
{
    private readonly MemoryCache _memoryCache;
    public AspNetCacheService()
    {
        _memoryCache = MemoryCache.Default;
    }

    public object Get(string key)
    {
        return _memoryCache[key];
    }

    public void Set(string key, object data)
    {
        _memoryCache[key] = data;
    }

    public object this[string key]
    {
        get { return _memoryCache[key]; }
        set { _memoryCache[key] = value; }
    }
}
キャッシュサービスの注入

アプリケーションの起動時にキャッシュサービスを注入するためのパブリックなRegisterCacheServiceメソッドを用意しておくと、コントローラごとにサービスを注入する必要はなく、テストもできるって訳ですね。
Global.asax.cs

public class MvcApplication : System.Web.HttpApplication
{
    protected void Application_Start()
    {
        ...

        RegisterCacheService(new AspNetCacheService());
        CacheService["StartTime"] = DateTime.Now.ToString();
    }

    private static ICacheService _internalCacheObject;

    public static void RegisterCacheService(ICacheService cacheService)
    {
        _internalCacheObject = cacheService;
    }

    public static ICacheService CacheService
    {
        get { return _internalCacheObject; }
    }
}


HomeController.cs

public class HomeController : Controller
{
    public ActionResult Index()
    {
        var data = MvcApplication.CacheService["StartTime"];
        if (data != null)
        {
            ViewBag.StartTime = (String)data;
        }

        return View();
    }
}

キャッシュサービスのテスト

テストの時はモックを用意してRegisterCacheServiceメソッドに渡してあげる感じ。
HomeControllerTests.cs

public class HomeControllerTests
{
    [TestMethod()]
    public void IndexTest_Cache()
    {
        var expected = "2017-04-15 12:00:00.000";
        var mockCacheService = new Mock<ICacheService>();
        mockCacheService.Setup(m => m["StartTime"]).Returns(expected);
        MvcApplication.RegisterCacheService(mockCacheService.Object);

        var controller = new HomeController();
        ViewResult result = controller.Index() as ViewResult;
        var actual = result.ViewBag.StartTime;

        Assert.AreEqual(expected, actual);
    }
}

実行結果

f:id:sh_yoshida:20170415173157p:plain

参考資料