Linq and lambdas with Moq

2,220 views
Skip to first unread message

SuneF

unread,
Feb 19, 2012, 8:35:36 AM2/19/12
to Moq Discussions
Hi I'm trying to get the results of linq queries specified with Moq.
I'm not sure it is possible, I couldn't find any examples. The code I
want to test does something similar as this (only a lot more complex):

int Foo(IContext context)
{
var q = context.list.Where(item => item.Price <
20).FirstOrDefault();
if (q != null)
... do something
else
... do something else.
}

Is it possible with Moq to achieve 100% coverage by mocking the
context?

Eg here I would like to force the Where in the linq expression to
always return null. I imagine it would be something like:

var mock = new Mock<IContext>();
mock.Setup(c => c.list.Where(...something here...)).Returns(null);
for instance
mock.Setup(c =>
c.list.Where(It.IsAny<LambdaExpression>()).Returns(null);

Hmm but it's not quite right I think...

Daniel Cazzulino

unread,
Feb 19, 2012, 1:40:46 PM2/19/12
to moq...@googlegroups.com
For that, I'd just roll a custom fake that uses lists. It's pretty trivial to do and is much more readable. 
--
Post: moq...@googlegroups.com
Unsubscribe: moqdisc-u...@googlegroups.com


--

/kzu

--
Daniel Cazzulino | Developer Lead | MS MVP | Clarius Consulting | +1 425.329.3471

Tim Kellogg

unread,
Feb 19, 2012, 2:30:05 PM2/19/12
to moq...@googlegroups.com
You can't mock extension methods because they're static. What you can do, however, is setup `.List` to return a list or array.

// A setup that fails the `if` b/c there's no items in the list
var mock = new Mock<IContext>();
mock.SetupGet(c => c.list).Returns(new ItemType[]{ });

// another setup that fails the `if` but b/c none of the items in the list satisfy the `.Where(...)` condition

var mock = new Mock<IContext>();
mock.SetupGet(c => c.list).Returns(new []{ new ItemType{ Price = 30 } });

// Another setup that passes 
var mock = new Mock<IContext>();
mock.SetupGet(c => c.list).Returns(new []{ new ItemType{ Price = 10 } });

Like kzu says, people who pick up this code after you will have a much easier time understanding these setups than had you actually mocked `.Where` and `.FirstOrDefault`

P.S. Your actual code can be simplified to `var q = context.list.FirstOrDefault(item => item.Price < 20);`. Since you've used lists to setup your mocks you can easily make this refactoring in confidence.

Regards,
--Tim



Daniel Cazzulino

unread,
Feb 19, 2012, 5:29:51 PM2/19/12
to moq...@googlegroups.com
I was suggesting more of a plain fake like this, but for non-dbcontext: http://blogs.clariusconsulting.net/kzu/how-to-design-a-unit-testable-domain-model-with-entity-framework-code-first/

Daniel Cazzulino

unread,
Feb 19, 2012, 6:10:19 PM2/19/12
to moq...@googlegroups.com
I was suggesting more of a plain fake like this, but for non-dbcontext: http://blogs.clariusconsulting.net/kzu/how-to-design-a-unit-testable-domain-model-with-entity-framework-code-first/

El domingo 19 de febrero de 2012, Tim Kellogg escribió:

SuneF

unread,
Feb 20, 2012, 4:23:05 AM2/20/12
to Moq Discussions
Hi and thanks for the replies.

The suggestions with returning the result of a collection like
mock.SetupGet(c => c.list).Returns(new []{ new ItemType{ Price =
30 } });
looks interesting, I didn't know that was possible.

I am trying to test code that uses the entity framework.
There are several ways I guess, a test database or a in-memory fake
database (this is doable now with T4 POCOs).
But I really want to use Moq so I can define only the data needed for
that particular unit test rather than rolling up an entire database
for each test. I also find that when I do test against a fake database
my unit tests usually fail, not because of errors in the code, but
because of data missing from the database *sigh*. And it's obviously
very cumbersome to manually fill a 30 table database with test data
suited for various unit tests.

Okay anyway, one of the simpler methods I'd like to test was this one:

List<VehicleDto> IStorage.GetVehicles()
{
AssertPrivilege((int)Privileges.ReadVehicle);

var result = new List<VehicleDto>();
var vehicles = user.Customer.Vehicles.Where(v => v.Enabled);

vehicles.ToList().ForEach(v =>
result.Add(Mapper.MapVehicleDto(v)));
return result;
}

The "user" is part of the IEntityModelContainer and happens to be the
user who is logged into the system.
So I am breaking the law of demeter here, but for the entity framework
this is quite normal.
Now, I think you see the problem. I can do something like:

var mock = new Mock<IEntityModelContainer>();
var vehicles = new MockObjectSet<Vehicle>() { };
var customers = new MockObjectSet<Customer>() { };
mock.SetupGet(c => c.Customers).Returns(customers);

but it's tricky getting things connected the right way...

Daniel Cazzulino

unread,
Feb 24, 2012, 9:45:48 AM2/24/12
to moq...@googlegroups.com
Moq is not a hammer turning every faking need into a nail (mock ;)).

Use plain in-memory fakes and lists when that's all you need, it's way simpler, and there's no hook-up to do.

/kzu

--
Daniel Cazzulino | Developer Lead | XML MVP | Clarius Consulting | +1 425.329.3471


Tim Kellogg

unread,
Feb 24, 2012, 10:18:45 AM2/24/12
to moq...@googlegroups.com
And on that topic, there's a super expensive mocking library that is that "hammer" turning every faking need into a nail. It's TypeMock. We evaluated it but decided against it because we thought it would make it all too easy to write badly designed code. But it certainly is all-powerful.

--Tim
Reply all
Reply to author
Forward
0 new messages