2016-10-10 101 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