Svi*_*ish 4 c# lambda unit-testing expression-trees
我有一个带有以下签名的扩展方法:
public static Expression<Func<T, bool>> And<T>(this Expression<Func<T, bool>> first, Expression<Func<T, bool>> second)
{
...
}
Run Code Online (Sandbox Code Playgroud)
我已经为它编写了一个测试用例,确保两个表达式实际上是组合在一起的.至少这样我的新表达式才有效.
现在我想编写另一个测试用例,确保该方法使用的短路版本and.任何线索我怎么能这样做?
我以为我可以这样做:
[Test]
public void And_PredicatesAreShortCircuited()
{
var predicateNotUsed = true;
Expression<Func<int, bool>> a = x => false;
Expression<Func<int, bool>> b = x =>
{
predicateNotUsed = false;
return true;
};
var foo = new[] { 1, 2, 3, 4, 5, 6, 7 }
.Where(a.And(b).Compile())
.ToArray();
Assert.That(predicateNotUsed);
}
Run Code Online (Sandbox Code Playgroud)
但是我在整个声明体下得到了一个巨大的红色波浪形,b表示"带有语句体的lambda表达式无法转换为表达式树".所以...任何选择?或者这是一个不可能的测试?
简单建议:使用引用类型而不是值类型,并在您不希望遵循的路径中取消引用它.传入null,看看它是否抛出异常:)
[Test]
public void And_PredicatesAreShortCircuited()
{
Expression<Func<string, bool>> a = x => false;
Expression<Func<string, bool>> b = x => x.Length > 10;
var foo = new[] { null, null }
.Where(a.And(b).Compile())
.ToArray();
}
Run Code Online (Sandbox Code Playgroud)
另一种选择是在输入数据上使用一些副作用函数(例如传递可以由表达式树改变的东西),但我认为以上可能是最简单的方法:)
或者另一个想法:
public T NonVoidFail(T x)
{
Assert.Fail("I shouldn't be called");
return x; // Will never happen
}
Run Code Online (Sandbox Code Playgroud)
然后:
[Test]
public void And_PredicatesAreShortCircuited()
{
Expression<Func<int, bool>> a = x => false;
Expression<Func<int, bool>> b = x => NonVoidFail(x);
var foo = new[] { 1, 2, 3, 4, 5, 6, 7 }
.Where(a.And(b).Compile())
.ToArray();
}
Run Code Online (Sandbox Code Playgroud)
这是相同的原则,但它会给你一个更好的例外:)