2011-07-11 23 views
13

我有工作执行的单位有(其中包括)以下方法:验证方法调用与Lambda表达式 - 起订量

T Single<T>(Expression<Func<T, bool>> expression) where T : class, new(); 

,我称呼它,比如,像这样:

var person = _uow.Single<Person>(p => p.FirstName == "Sergi"); 

如何验证Single方法已被调用,参数为FirstName == "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)); 

他们都导致如下因素的错误:

Expected invocation on the mock at least once, but was never performed

如何任何想法,可以做什么? 我使用的是最新的Moq从的NuGet,版本4.0.10827.0

更新:一个具体的例子

我所看到的是,每当我用的是拉姆达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); 
} 

怎么来的Verify,只要我使用的方法参数的lambda表达式失败?

写这个测试的正确方法是什么?

回答

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)); 
} 

并且如上面的测试表明, PRESSION身体也会失败,但字符串比较有效,所以这个作品,以及:

// 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()); 
} 

正如你有很多测试用例不合格,你可能会遇到不同的问题。

UPDATE:根据您的更新,请考虑以下设置和表达式:

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,则表达式与表达式右侧的每个参考a const再次相同。

+0

非常感谢您的回答。我根据新的呃...发现更新了我的问题,因为缺乏更好的单词。有任何想法吗? –

+0

我已更新我的问题以解决可能是您的问题。这真的取决于QuestionnaireType.Objective的类型。我期望如果你使用'ToString()'这两个表达式,你会发现它们是不同类型的。 –

+0

再次感谢,我想是有道理的。但是,那么编写这个测试的正确方法是什么呢?我觉得在这种情况下,嘲笑是阻碍,而不是一个更清晰的代码的工具... –

1

我还想分享另一种方法来比较参数表达式与预期表达式。我搜索的StackOverflow的 “如何比较表达式,” 我被带到了这些文章:

我当时导致this Subversion repositorydb4o.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))));

最终,ExpressionEqualityComparerToString()技术无论是在这种情况下返回true(与ToString最有可能的是速度更快 - 未经测试)。就我个人而言,我更喜欢比较器方法,因为我觉得它比较自我记录,并且更好地反映了您的设计意图(比较表达式对象而不是它们的ToString输出的字符串比较)。

说明:我仍然在寻找一个db4o.net许可证文件在这个项目中,但我还没有修改代码,包括版权声明和(因为该网页是公开的)我假设现在已经足够了...... ;-)