问题
The Shouldly assertion library for .NET somehow knows what expression the assertion method was called on so it is able to display it into the message. I tried to find out how it works but got lost in the source code. I suspect it looks into the compiled code but I would really like to see how this happens. From the documentation
map.IndexOfValue("boo").ShouldBe(2); // -> map.IndexOfValue("boo") should be 2 but was 1
Somehow Shouldly knows the expression map.IndexOfValue("boo") and was able to display it in the test failure message. Does anyone know how this happens?
回答1:
Looking at the code, that's pretty smart.
The magic is happening in the ActualCodeTextGetter
class. First, it retrieves the line of the source code file by using the StackTrace:
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;
Once it has the name of the source code file, along with the line and offset of the statement, it's just a matter of reading directly the file:
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;
}
There's a lot more logic going on to isolate precisely the statement, but in short the trick is:
- Use the StackTrace to retrieve the location of the source code and the line of the statement
- Parse the source code to retrieve the exact statement
Of course, it can work only if you're running it on the same machine you used to compile the code.
回答2:
It does it by parsing the stack trace for the current call stack until it finds a method that is not internal to Shouldly and treats its name as the name of the method under test.
来源:https://stackoverflow.com/questions/39959272/how-does-the-shouldly-assertion-library-know-the-expression-the-assertion-was-ap