views:

95

answers:

1

Lets say I have a Customers table and an Orders table with a one-to-many association (one customer can have multiple orders). If I have some code that I wish to unit test that accesses a specific customer's orders via lazy-loading (e.g. a call to customer.Orders), how do I mock / stub that call out so that it doesn't hit the database?

Edit:

To be more clear, let's use a more concrete example. Let's say I want to return all the orders for a particular customer. I could write it like so using the auto-generated lazy-loading properties Linq 2 Sql provides:

Customer customer = customerRepository.GetCustomerById(customerId);

return customer.Orders;

However, unit testing this is a bit tough. I can mock out the call to GetCustomerById, but I can't (as far as I can tell) mock out the call to Orders. The only way I can think of to unit test this would be to either a) connect to a database (which would slow down my tests and be fragile) or b) don't use lazy-load properties.

Not using lazy-load properties, I would probably rewrite the above as this:

return orderRepository.GetOrdersByCustomerId(customerId);

This definitely works, but it feels awkward to completely ignore lazy-load properties simply for unit-testing.

+1  A: 

As an overall answer to your question, you stub out that call just as you stub out anything else.

I will assume that the code you want to unit test is a consumer of your data access component, as this is the most common scenario. You can only stub out you data access if you program against an interface. This means that you must hide the implementation details of L2S behind an interface such that the consuming code has no idea about which implementation it currently consumes.

A corrolary to this is that lazy-loading is an implementation detail you you need not worry about when unit testing, because the unit test should not be using L2S at all.

When stubbing out the data access layer, a call to customers.Orders would typically be a call to an in-memory property of the Stub.

Mark Seemann
In other words, don't use the automatically generated lazy-load properties? Instead of calling customer.Orders (where customer is of type Customer, created by Linq 2 Sql) you would create an OrderRepository that implements IOrderRepository and stub that out? That's what I've been doing, but it seems a waste to completely ignore using the lazy-loading features of Linq 2 Sql...
Kevin Pang
Yes, that's just what I mean, but just because you program against an interface that is oblivious to implementation details doesn't mean that you can't use those features. If you find the lazy-loading features of L2S valuable, then by all means use them, but you must do that in a manner where the consumer is ignorant about those details. The current ORM technologies of Microsoft (L2S and EF) aren't particularly well-suited to this way of working with data access, but FWIW the next version of EF should get true persistence ignorance...
Mark Seemann
Makes sense. I figured that might be the case, but was hoping that it wasn't and that I was just missing something. I guess I'll just ignore the lazy-loading features for now for the sake of unit testing.
Kevin Pang