2009/11/22

VisualStudio 2008の単体テスト機能のカスタマイズ(VS2008 custom assertion example)

結構前にGallioAssertEx.Thatの式ツリーの要素をキャプチャして出力できる点がすごいと思ってちょっといろいろいじっていた。Gallioは素晴らしいけどちょっと重い感じがするし、機能とか装備されているものが豊富なのはいいんだけど、もうちょっと簡単にいじれる大きすぎないフレームワークを使いたいというのが感想。
最近それをある程度の形にしようと思って、アレンジしてVisual Studio 2008の単体テスト機能で使えるようにしようとしてVisual Studio 2008の単体テスト機能のカスタマイズを調べてみた。

基本的には自前のassertionでテスト失敗の場合はAssertFailedExceptionをスローすればいいんだけど、そうするとスタックトレースに診断処理や例外をスローする処理のメソッドが含まれてしまう。
これはDebuggerHiddenAttributeDebuggerNonUserCodeAttributeを使っても避けられない。デバッガとスタックトレースは別。


スタックトレースに含まれないように回避するための属性はないみたいなので、スタックトレースを操作する方向で行こうとすると例外のスタックトレース(Exception.StackTraceプロパティとか)はStackTrace型ではなくて文字列だったりする上にSetterがない。
どうすればいいの?例外のスタックトレースは変更できないの?と思ったけどよく見るとException.StackTraceプロパティはvirtual宣言されているから派生させてオーバーライドすれば、このプロパティで返される値は変更できる。

それでこんなコードでスタックトレースに含められないようにできそう。
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace MSTestCustomAssertion
{
    public class ExpressionAssert
    {
        public static void IsTrue(Expression<Func<bool>> expr)
        {
            var result = expr.Compile().Invoke();
            if (!result)
                throw new FailedException("ExpressionAssert.IsTrue failed");
        }

        public class FailedException : AssertFailedException
        {
            public FailedException() : base() { }
            public FailedException(string msg) : base(msg) { }
            public override string StackTrace
            {
                get
                {
                    var lines = base.StackTrace.Split(new string[] { Environment.NewLine, }, StringSplitOptions.None);
                    var index = Array.FindIndex(lines, x => !x.Contains("ExpressionAssert."));
                    var st = string.Join(Environment.NewLine, lines, index, lines.Length - index);
                    return st;
                }
            }
        }
    }
}
ksksts / junk / source — bitbucket.org

Visual Studioの単体テスト機能でテストを失敗させた場合のスタックトレースにExpressionAssertクラスの処理が含まれない。


Visual Studioに統合された単体テストの機能以外で試してもいないし、例外クラスがAssertFailedExceptionではないという点が気になるけど、とりあえず手軽にするならこの方法でもいいかもしれない。

手間は増えるだろうけどInternalPreserveStackTraceを使ったやり方のほうがちゃんとしていそう。

0 件のコメント: