2016-10-10 49 views
16

Shouldly assertion library for .NET以某种方式知道断言方法被调用了什么表达式,所以它能够将它显示在消息中。我试图找出它是如何工作的,但在源代码中丢失了。我怀疑它看着编译的代码,但我真的很想看看这是怎么发生的。从文档Shouldly断言库如何知道断言适用的表达式?

map.IndexOfValue("boo").ShouldBe(2); // -> map.IndexOfValue("boo") should be 2 but was 1 

不知何故Shouldly知道表达map.IndexOfValue(“嘘声”),并能够在测试失败消息来显示它。有谁知道这是怎么发生的?

回答

15

看着代码,这很聪明。

魔法发生在ActualCodeTextGetter类。首先,它使用堆栈跟踪检索的源代码文件的行:

StackTrace stackTrace = trace ?? new StackTrace(true); 

    // Cut for brevity 

    StackFrame stackFrame = frame; 
    this.ShouldlyFrameIndex = index - 1; 
    string fileName = stackFrame.GetFileName(); 
    this._determinedOriginatingFrame = fileName != null && File.Exists(fileName); 
    this._shouldMethod = this.ShouldlyFrame.GetMethod().Name; 
    this.FileName = fileName; 
    this.LineNumber = stackFrame.GetFileLineNumber() - 1; 

一旦它的源代码文件的名称,与它一同和声明的偏移量,它只是一个阅读材料直接文件:

private string GetCodePart() 
{ 
    string str = "Shouldly uses your source code to generate its great error messages, build your test project with full debug information to get better error messages\nThe provided expression"; 
    if (this._determinedOriginatingFrame) 
    { 
    string codeLines = string.Join("\n", ((IEnumerable<string>) File.ReadAllLines(this.FileName)).Skip<string>(this.LineNumber).ToArray<string>()); 
    int indexOfMethod = codeLines.IndexOf(this._shouldMethod); 
    if (indexOfMethod > 0) 
     str = codeLines.Substring(0, indexOfMethod - 1).Trim(); 
    str = !str.EndsWith("Should") ? str.RemoveVariableAssignment().RemoveBlock() : this.GetCodePartFromParameter(indexOfMethod, codeLines, str); 
    } 
    return str; 
} 

还有很多更多的逻辑回事精确孤立的语句,但在很短的诀窍是:

  • 使用堆栈跟踪检索源共同的位置德及本声明
  • 线分析源代码以获取准确的说法

当然,它可以,如果你你用来编译的代码在同一台机器上运行它才能正常工作。

+0

令人惊叹。测试库包含最疯狂的技巧。 – Stilgar