最近それをある程度の形にしようと思って、アレンジしてVisual Studio 2008の単体テスト機能で使えるようにしようとしてVisual Studio 2008の単体テスト機能のカスタマイズを調べてみた。
基本的には自前のassertionでテスト失敗の場合はAssertFailedExceptionをスローすればいいんだけど、そうするとスタックトレースに診断処理や例外をスローする処理のメソッドが含まれてしまう。
これはDebuggerHiddenAttributeやDebuggerNonUserCodeAttributeを使っても避けられない。デバッガとスタックトレースは別。
スタックトレースに含まれないように回避するための属性はないみたいなので、スタックトレースを操作する方向で行こうとすると例外のスタックトレース(Exception.StackTraceプロパティとか)はStackTrace型ではなくて文字列だったりする上にSetterがない。
どうすればいいの?例外のスタックトレースは変更できないの?と思ったけどよく見るとException.StackTraceプロパティはvirtual宣言されているから派生させてオーバーライドすれば、このプロパティで返される値は変更できる。
それでこんなコードでスタックトレースに含められないようにできそう。
using System;ksksts / junk / source — bitbucket.org
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;
}
}
}
}
}
Visual Studioの単体テスト機能でテストを失敗させた場合のスタックトレースにExpressionAssertクラスの処理が含まれない。
Visual Studioに統合された単体テストの機能以外で試してもいないし、例外クラスがAssertFailedExceptionではないという点が気になるけど、とりあえず手軽にするならこの方法でもいいかもしれない。
手間は増えるだろうけどInternalPreserveStackTraceを使ったやり方のほうがちゃんとしていそう。
0 件のコメント:
コメントを投稿