我有一个工作单元实现,其中包含以下方法:
T Single<T>(Expression<Func<T, bool>> expression) where T : class, new();
例如,我这样调用它:
var person = _uow.Single<Person>(p => p.FirstName == "Sergi");
如何验证 Single
方法是否已使用参数 < 调用代码>名字==“Sergi”?
我已尝试以下方法,但无济于事:
// 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));
它们都会导致以下错误:
预期对模拟至少调用一次,但从未执行
关于如何做到这一点的任何想法?
我使用的是 NuGet 的最新 Moq,版本 4.0.10827.0
更新:一个具体的例子
我所看到的是,每当我在 lambda 中使用字符串文字时,Verify
就会起作用。一旦我比较变量,它就会失败。举个例子:
// 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);
}
为什么只要我在 lambda 表达式中使用方法参数,Verify
就会失败?
编写此测试的正确方法是什么?
I have a Unit of Work implementation with, among others, the following method:
T Single<T>(Expression<Func<T, bool>> expression) where T : class, new();
and I call it, for instance, like this:
var person = _uow.Single<Person>(p => p.FirstName == "Sergi");
How can I verify that the Single
method has been called with an argument of FirstName == "Sergi"
?
I've tried the following, but to no avail:
// 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));
They all result in the folowing error:
Expected invocation on the mock at least once, but was never performed
Any ideas on how that can be done?
I'm using the latest Moq from NuGet, version 4.0.10827.0
UPDATE: A Specific example
What I'm seeing is that whenever I use string literals inside the lambda, Verify
works. As soon as I'm comparing variables it fails. Case in point:
// 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);
}
How come the Verify
fails as soon as I use the method parameter in the lambda expression?
What would be the proper way to write this test?
发布评论
评论(2)
直接方法对我来说效果很好:
表达式对象不会为等效表达式返回 true,因此这将失败:
要了解原因,请运行以下 NUnit 测试:
并且如上面的测试所示,通过表达式主体进行比较也会失败,但字符串比较有效,所以这也有效:
这是您可以添加到同样有效的工具库中的另一种测试样式:
由于您有许多不应该失败的测试用例,因此您可能会遇到不同的问题。
更新:根据您的更新,请考虑以下设置和表达式:
一个表达式引用包含方法的实例变量。另一个表示引用静态类的 const 成员的表达式。无论在运行时分配给变量的值如何,两者都是不同的表达式。但是,如果将
string normal_type
更改为const string normal_type
,则表达式再次相同,因为每个引用右侧的const
的表达。The direct approach works just fine for me:
The expression object doesn't return true for equivalent expressions so this will fail:
To understand why, run the following NUnit test:
And as the test above indicates, comparing by the expression body will also fail, but string comparison works, so this works as well:
And here's one more style of test you can add to the arsenal that also works:
As you have a number of test cases that fail that shouldn't, you likely have a different problem.
UPDATE: Per your update, consider the following setup and expressions:
One expression references an instance variable of the containing method. The other represents an expression that references a const member of a static class. The two are different expressions, regardless of the values that may be assigned to the variables at runtime. If however,
string normal_type
is changed toconst string normal_type
then the expressions are again the same as each reference aconst
on the right hand side of the expression.我还想分享另一种将参数表达式与预期表达式进行比较的方法。我在 StackOverflow 中搜索“如何比较表达式”,结果找到了以下文章:
然后我被引导到此 Subversion 存储库对于 db4o.net。在他们的一个项目(命名空间
Db4objects.Db4o.Linq.Expressions
)中,它们包含一个名为ExpressionEqualityComparer
的类。我能够从存储库中检出该项目,编译、构建并创建一个 DLL 以在我自己的项目中使用。使用
ExpressionEqualityComparer
,您可以将Verify
调用修改为如下所示:session.Verify(x => x>>(e =>;
.Single(It.Is<表达式
new ExpressionEqualityComparer().Equals(e, expression))));
最终,在这种情况下,
ExpressionEqualityComparer
和ToString()
技术都返回 true (其中ToString
很可能更快 - 速度未测试)。就我个人而言,我更喜欢比较器方法,因为我觉得它更具自我记录性,并且更好地反映您的设计意图(比较表达式对象而不是其 ToString 输出的字符串比较)。注意:我仍在这个项目中寻找 db4o.net 许可证文件,但我没有修改代码,包括版权声明,并且(因为该页面是公开可用的)我想现在就足够了......;-)
I would also like to share another approach to comparing the parameter expression to the expected expression. I searched StackOverflow for "how to compare expressions," and I was led to these articles:
I was then led to this Subversion repository for db4o.net. In one of their projects, namespace
Db4objects.Db4o.Linq.Expressions
, they include a class namedExpressionEqualityComparer
. I was able to checkout this project from the repository, compile, build, and create a DLL to use in my own project.With the
ExpressionEqualityComparer
, you can modify theVerify
call to something like the following:session.Verify(x => x
.Single(It.Is<Expression<Func<Person, bool>>>(e =>
new ExpressionEqualityComparer().Equals(e, expression))));
Ultimately, the
ExpressionEqualityComparer
and theToString()
techniques both return true in this case (with theToString
most likely being faster - speed not tested). Personally, I prefer the comparer approach since I feel it is more self-documenting and better reflects your design intent (comparing the expression objects rather a string comparison of their ToString outputs).Note: I'm still looking for a db4o.net license file in this project, but I've not modified the code in anyway, included the copyright notice, and (since the page is publicly available) I'm assuming that's enough for now... ;-)