Да, даже если Вы - единственное управление исходным кодом человека, необходимость. Конечно, Вы не будете использовать его для управления, кто работает, на которых файлах, но наличии способности к роли, назад если Вы делаете большую ошибку в своем коде, действительно легкая задача.
Вы можете получить код, если это отладочная сборка, используя некоторые классы диагностики. Учитывая, что это для модульных тестов, DEBUG, вероятно, разумен.
public static void ShouldBe<T>(this T actual, T expected)
{
var frame = new StackTrace(true).GetFrame(1);
var fileName = frame.GetFileName();
var lineNumber = frame.GetFileLineNumber() - 1;
string code = File.ReadLines(fileName).ElementAt(lineNumber).Trim();
Debug.Assert(actual.Equals(expected), code);
}
Для вашего примера code = "steve.BrainsConsumed.ShouldBe (0);"
Очевидно, вам следует добавить некоторую ошибку проверяя этот код, и вы, вероятно, могли бы сделать это быстрее, не читая все строки в файле.
Лучшее, что я могу сделать, это:
steve.Property(p => p.BrainsConsumed).ShouldBe(0);
или:
steve.ShouldBe(p => p.BrainsConsumed, 0);
или:
Assert.AreEqual(() => steve.BrainsConsumed, 0);
Re:
Бонусными баллами будет переменная экземпляра
. При использовании Expression
(или просто Expression
) вы можете довольно легко получить имя и значение свойства. Я' Я сделаю пример для середины - обратите внимание, что для первого требуется дополнительный тип для DSL, но ничего тяжелого:
public static class Test
{
public static void AssertEqual<TSource, TValue>(
this TSource source,
Expression<Func<TSource, TValue>> selector,
TValue expected)
where TSource : class
{
TValue value = selector.Compile()(source);
string paramName = selector.Parameters[0].Name;
System.Diagnostics.Debug.Assert(
EqualityComparer<TValue>.Default.Equals(value, expected),
typeof(TSource) + " " + paramName + ": " +
value + " doesn't match expected " + expected);
}
}
Или чуть лучше сообщение:
public class Zombie
{
public int BrainsConsumed { get; set; }
static void Main() {
Zombie steve = new Zombie { BrainsConsumed = 2 };
Test.ShouldBeEqual(() => steve.BrainsConsumed, 0);
}
}
public static class Test
{
static string GetName(Expression expr)
{
if (expr.NodeType == ExpressionType.MemberAccess)
{
var me = (MemberExpression)expr;
string name = me.Member.Name, subExpr = GetName(me.Expression);
return string.IsNullOrEmpty(subExpr)
? name : (subExpr + "." + name);
}
return "";
}
public static void ShouldBeEqual<TValue>(
Expression<Func<TValue>> selector,
TValue expected)
{
TValue value = selector.Compile()();
string name = GetName(selector.Body);
System.Diagnostics.Debug.Assert(
EqualityComparer<TValue>.Default.Equals(value, expected),
typeof(TValue) + " " + name + ": " +
value + " doesn't match expected " + expected);
}
}
Нет, я не думаю, что сможете.
Предположим, что BrainsConsumed - целое число (что выглядит вероятным). В этом случае параметр передается по значению - все, что вы получаете, - это копия тестируемого целого числа. У него нет имени, кроме имени в локальной области (фактического).
Этот аналогичный вопрос может прояснить:
Это позволит вам протестировать его, но не даст вам имя метода.
У вас может быть это расширение:
public static void ShouldBe<T>(this Func<T> func, T expected)
{
Assert.AreEqual(func(), expected);
}
Со следующим использованием:
((Func<int>)Program.TestMethod).ShouldBe(2);
К сожалению, в этой позиции вы не сможете получить имя свойства на этом этапе. Проблема в том, что вы передаете значение поля BrainsConsumed, и в этот момент просто нет обратной ссылки на Zombie (что касается вашего метода, это int, и он не может сработать, откуда изначально пришел int from).
Лучшее, что я мог придумать для вас, - это то, что Environment.StackTrace будет содержать соответствующую информацию, так как вы вызвали steve.BrainsConsumed на 1 шаг вверх по стеку (рекомендуется только в том случае, если вы пытаюсь понять, что не удалось в ваших модульных тестах - не если они действительно проходят по стеку в обычном потоке программы).