如何测试我的stacktrace walker是否正确跳过了库代码

时间:2018-11-29 22:10:09

标签: c# unit-testing exception-handling

我的问题是:我试图跳过一些来自库代码的堆栈框架。如果要对此进行测试,如何最好/最容易地实现一种情况,即stacktrace的顶部有一个或多个来自库代码的框架?

详细信息:

我使用以下代码的目标是能够在我的源代码中记录异常的起源。但是,在某些情况下,异常是在库代码中触发的,因此我得到了如下所示的堆栈跟踪:

  

System.Net.WebException:操作已超时
         在System.Net.HttpWebRequest.GetRequestStream(TransportContext&context)
         在System.Net.HttpWebRequest.GetRequestStream()
         在Microsoft.Bing.Platform.ConversationalUnderstanding.ObjectStore.ObjectStoreClientHelperClass.d__7''2.MoveNext()
      ---从先前引发异常的位置开始的堆栈跟踪---
         在System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
         在System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(任务任务)
         在Microsoft.Bing.Platform.ConversationalUnderstanding.ObjectStore.ObjectStoreCoprocRequest.d__10`4.MoveNext()
      ---从之前引发异常的位置开始的堆栈结束跟踪---       

因此,基本上,我想在堆栈框架上继续前进,直到找到一个真正有用的信息为止,并跳过那些没有真正告诉我任何有用信息的库方法。

这是我要测试的代码:

public static (string Path, string Method, int Line) TryGetExceptionOrigin(this Exception e, string defaultPath, string defaultMethod, int defaultLine)
{
    var defaultRes = (Path: defaultPath, Method: defaultMethod, Line: defaultLine);
    var st = new StackTrace(e.GetInnerMostException(), true);
    if (st.FrameCount == 0)
    {
        return defaultRes;
    }

    // Walk down the stack, ignoring framework code etc. with no useful information. We need a file name to be happy
    for (int i = 0; i < st.FrameCount; i++)
    {
        var bottomFrame = st.GetFrame(i);
        if (!(string.IsNullOrEmpty(bottomFrame.GetFileName())))
        {
            return (
            Path: bottomFrame.GetFileName() ?? string.Empty, // Is null if no debug information
            Method: bottomFrame.GetMethod().Name, // Documentation does not say this can ever be null
            Line: bottomFrame.GetFileLineNumber()); // Is 0 if no debug information
        }
    }

    // OK no match, we return the default information
    return defaultRes;
}

2 个答案:

答案 0 :(得分:0)

一些不必要的复杂处理应该很好:

try
{
    Func<int> d = () =>
    {
        try
        {
            return Guid.Parse("*").ToByteArray()[0];
        }
        catch (Exception)
        {
            throw;
        }
    };
    Action a = () => { String.Format("{0}", 1 / d()); };
    a();
}
catch (Exception ex)
{
    var useful = ex.TryGetExceptionOrigin(null, null, 0);
}

此示例将导致一个异常调用堆栈,其中包含三个用户代码和四个框架/库代码条目。

答案 1 :(得分:0)

https://dotnetthoughts.wordpress.com/2007/10/27/where-did-my-exception-occur/找到它

    private static void ThrowIt()
    {
        Divide(3M, 0M);
    }

    static decimal Divide(decimal a, decimal b)
    {
        return (a / b);
    } 

这将产生以下堆栈跟踪:

  

st {
  在System.Decimal.FCallDivide(Decimal&d1,Decimal&d2)
  在System.Decimal.op_Division(Decimal d1,Decimal d2)
  在C:\ Users \ anjohans \ source \ repos \ ExceptionLogging \ ExceptionLogging \ Program.cs:line的ExceptionLogging.Program.Divide(十进制a,十进制b)中   98在ExceptionLogging.Program.ThrowIt()中   C:\ Users \ anjohans \ source \ repos \ ExceptionLogging \ ExceptionLogging \ Program.cs:line   93在ExceptionLogging.Program.ThrowLater()中   C:\ Users \ anjohans \ source \ repos \ ExceptionLogging \ ExceptionLogging \ Program.cs:line   88在ExceptionLogging.Program.Main(String [] args)中   C:\ Users \ anjohans \ source \ repos \ ExceptionLogging \ ExceptionLogging \ Program.cs:line   17} System.Diagnostics.StackTrace