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?
The direct approach works just fine for me:
// direct approach session.Verify(x => x.Single<Person>(p => p.FirstName == "Sergi"));
The expression object doesn't return true for equivalent expressions so this will fail:
// 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));
To understand why, run the following NUnit test:
[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)); }
And as the test above indicates, comparing by the expression body will also fail, but string comparison works, so this works as well:
// even their string representations! session.Verify(x => x .Single(It.Is<Expression<Func<Person, bool>>>(e => e.ToString() == expression.ToString()));
And here's one more style of test you can add to the arsenal that also works:
[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()); }
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:
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;
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 to const string normal_type
then the expressions are again the same as each reference a const
on the right hand side of the expression.
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 named ExpressionEqualityComparer
. 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 the Verify
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 the ToString()
techniques both return true in this case (with the ToString
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... ;-)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With