我有一个工作单元实施,其中包括以下方法:
T Single<T>(Expression<Func<T, bool>> expression) where T : class, new();
我打电话给它,例如,像这样:
var person = _uow.Single<Person>(p => p.FirstName == "Sergi");
如何验证Single
方法是否已使用[{1}}参数调用?
我尝试了以下内容,但无济于事:
FirstName == "Sergi"
它们都会导致以下错误:
模拟上的预期调用至少一次,但从未执行过
关于如何做到这一点的任何想法? 我正在使用NuGet的最新版Moq,版本4.0.10827.0
更新:具体示例
我所看到的是,每当我在lambda中使用字符串文字时,// direct approach
session.Verify(x => x.Single<Person>(p => p.FirstName == "Sergi"));
// comparing expressions
Expression<Func<Person, bool>> expression = p => p.FirstName == "Sergi");
session.Verify(x => x
.Single(It.Is<Expression<Func<Person, bool>>>(e => e == expression));
都能正常工作。一旦我比较变量就失败了。一个很好的例子:
Verify
在lambda表达式中使用method参数后,// the verify
someService.GetFromType(QuestionnaireType.Objective)
session.Verify(x => x.Single<Questionnaire>(q =>
q.Type == QuestionnaireType.Objective));
// QuestionnaireType.Objective is just a constant:
const string Objective = "objective";
// the method where it's called (FAILS):
public Questionnaire GetFromType(string type)
{
// this will fail the Verify
var questionnaire = _session
.Single<Questionnaire>(q => q.Type == type);
}
// the method where it's called (PASSES):
public Questionnaire GetFromType(string type)
{
// this will pass the Verify
var questionnaire = _session
.Single<Questionnaire>(q => q.Type == QuestionnaireType.Objective);
}
怎么会失败?
编写此测试的正确方法是什么?
答案 0 :(得分:11)
直接方法对我来说很合适:
// direct approach
session.Verify(x => x.Single<Person>(p => p.FirstName == "Sergi"));
对于等效表达式,表达式对象不返回true,因此这将失败:
// comparing expressions
Expression<Func<Person, bool>> expression = p => p.FirstName == "Sergi");
session.Verify(x => x
.Single(It.Is<Expression<Func<Person, bool>>>(e => e == expression));
要了解原因,请运行以下NUnit测试:
[Test]
public void OperatorEqualEqualVerification()
{
Expression<Func<Person, bool>> expr1 = p => p.FirstName == "Sergi";
Expression<Func<Person, bool>> expr2 = p => p.FirstName == "Sergi";
Assert.IsTrue(expr1.ToString() == expr2.ToString());
Assert.IsFalse(expr1.Equals(expr2));
Assert.IsFalse(expr1 == expr2);
Assert.IsFalse(expr1.Body == expr2.Body);
Assert.IsFalse(expr1.Body.Equals(expr2.Body));
}
正如上面的测试所表明的那样,通过表达体进行比较也会失败,但字符串比较也会起作用,所以这也有效:
// even their string representations!
session.Verify(x => x
.Single(It.Is<Expression<Func<Person, bool>>>(e =>
e.ToString() == expression.ToString()));
这里还有一种测试方式,你可以添加到也适用的工具库中:
[Test]
public void CallbackVerification()
{
Expression<Func<Person, bool>> actualExpression = null;
var mockUow = new Mock<IUnitOfWork>();
mockUow
.Setup(u => u.Single<Person>(It.IsAny<Expression<Func<Person, bool>>>()))
.Callback( (Expression<Func<Person,bool>> x) => actualExpression = x);
var uow = mockUow.Object;
uow.Single<Person>(p => p.FirstName == "Sergi");
Expression<Func<Person, bool>> expectedExpression = p => p.FirstName == "Sergi";
Assert.AreEqual(expectedExpression.ToString(), actualExpression.ToString());
}
由于您有许多不应该失败的测试用例,您可能会遇到其他问题。
更新:根据您的更新,请考虑以下设置和表达式:
string normal_type = "NORMAL";
// PersonConstants is a static class with NORMAL_TYPE defined as follows:
// public const string NORMAL_TYPE = "NORMAL";
Expression<Func<Person, bool>> expr1 = p => p.Type == normal_type;
Expression<Func<Person, bool>> expr2 = p => p.Type == PersonConstants.NORMAL_TYPE;
一个表达式引用包含方法的实例变量。另一个表示引用静态类的const成员的表达式。无论在运行时可能分配给变量的值如何,这两者都是不同的表达式。但是,如果string normal_type
更改为const string normal_type
,则表达式再次与表达式右侧的每个引用const
相同。
答案 1 :(得分:1)
我还想分享另一种方法来将参数表达式与预期表达式进行比较。我在StackOverflow中搜索了#34;如何比较表达式,&#34;我被引导到这些文章:
然后我被引导到this Subversion repository db4o.net。在其中一个项目名称空间Db4objects.Db4o.Linq.Expressions
中,它们包含一个名为ExpressionEqualityComparer
的类。我能够从存储库中检出这个项目,编译,构建和创建一个DLL,以便在我自己的项目中使用。
使用ExpressionEqualityComparer
,您可以将Verify
调用修改为以下内容:
session.Verify(x => x
.Single(It.Is<Expression<Func<Person, bool>>>(e =>
new ExpressionEqualityComparer().Equals(e, expression))));
最终,ExpressionEqualityComparer
和ToString()
技术在这种情况下都返回true(ToString
最有可能更快 - 未经测试的速度)。就个人而言,我更喜欢比较器方法,因为我觉得它更自我记录并且更好地反映了你的设计意图(比较表达式对象而不是它们的ToString输出的字符串比较)。
注意:我仍然在这个项目中寻找db4o.net许可文件,但我还没有修改代码,包括版权声明,以及(由于页面是公开的,我现在假设已经足够......; - )