tags:

views:

68

answers:

2

Please help this Linq newbie!

I'm creating a list inside my class under test, and I would like to use Moq to check the results.

I can easily put together a Predicate which checks the results of the list. How do I then make that Predicate into an Expression?

var myList = new List<int> {1, 2, 3};

Predicate<List<int>> myPredicate = (list) => 
                  {
                      return list.Count == 3; // amongst other stuff
                  };

// ... do my stuff

myMock.Verify(m => m.DidStuffWith(It.Is<List<int>>( ??? )));

??? needs to be an Expression<Predicate<List<int>>> if you can get your head round that many generics. I've found answers which do this the other way round and compile an Expression into a Predicate. They're not helping me understand Linq any better, though.

EDIT: I've got it working with methods; with expressions; I would just like to know if there's any way to do it with a lambda with a body - and if not, why not?

+1  A: 

Change:

Predicate<List<int>> myPredicate = (list) => list.Count == 3;

To:

Expression<Predicate<List<int>>> myPredicate = (list) => list.Count == 3;

The compiler does the magic for you. Any lambda dealing only with expressions (no blocks) can be converted into an expression tree by wrapping the delegate type (in this case Predicate<List<int>>) with Expression<>. As you noted, you could then invert it yet again by calling myPredicate.Compile().

Update: You simply cannot use the compiler to arrive at the expression tree you want if it includes statements. You'll have to build up the expression tree yourself (a lot more work) using the static methods in Expression. (Expression.Block, Expression.IfThen, etc.)

Kirk Woll
This works with an expression but not with a lambda with an expression body. Updated to include that in my example. Thank you for teaching me that bit though; I hadn't tried it without the brackets.
Lunivore
@Kirk Woll: "Any lambda can be converted into an expression tree." This is false. Consider lambdas that have an expression body.
Jason
@Jason, thanks, updated to reflect that nuance.
Kirk Woll
Anyone able to explain what it is about the nature of expression trees that prevents this? Or is it just that they compile into something horribly (or beautifully) functional and functions can't contain state?
Lunivore
@Lunivore, please see Eric Lippert's answer here: http://stackoverflow.com/questions/1430738/what-is-the-max-linq-expression-trees-can-do : "That is an obvious and useful feature which we simply did not have time to get to for C# 4. We'll consider it for hypothetical future versions. If you have a really great user scenario for statement trees, I'd love to hear it."
Kirk Woll
@Kirk Woll, thanks. I've just updated Eric's answer since this is obviously a really great user scenario.
Lunivore
A: 

Kirk Woll's answer directly addresses your question, but consider the fact that you can use the Callback method on a Setup of a void method to handle the parameters which were passed in on invocation. This makes more sense to me since you're already having to build a method to validate the list anyway; it also gives you a local copy of the list.

//what is this list used for?
var myList = new List<int> {1, 2, 3};

List<int> listWithWhichStuffWasDone = null;
//other setup

myMock.Setup(m => m.DoStuffWith(It.IsAny<List<int>>()).
    Callback<List<int>>(l => listWithWhichStufFWasDone = l);

objectUnderTest.MethodUnderTest();

myMock.Verify(m => m.DoStuffWith(It.IsAny<List<int>>()));
Validate(listWithWhichStuffWasDone);
arootbeer
If I was trying to Setup a method, sure. However, I'm using Verify. I dislike the whole Given, Expect, When, Then go back and re-read everything because your desired outcome happened somewhere bizarre in the middle, so Setup isn't going to cut it. I prefer the outcome to be at the end of the test. It's more readable that way.
Lunivore
(I used a method instead btw - that solved the problem. And got a thank you from Eric. So thank you too!)
Lunivore
Interesting - I came to Moq from Rhino Mocks (late 2.x or early 3.x IIRC) where you had to set everything up explicitly. I noticed that you don't have to do that with Moq, but I'd never thought about leaving off the Arrange part and just Asserting at the end.
arootbeer