views:

226

answers:

2

We are building an ASP.NET MVC site, and I'm struggling with where to define a connection to best enable unit testing (I use 'connection' generically - it could be a session, a connection, an adapter, or any other type of data context that can manage transactions and database operations).

Let's say we have 3 classes:

UserController
UserService
UserRepository

In the past, we'd do something like this within a method of the UserService:

Using (ISomeSession session = new SomeSession())
{
  session.StartTransaction();
  IUserRepository rep = new UserRepository(session);
  rep.DoSomething();
  rep.Save();
  session.Commit();
}

However, it wasn't really possible to unit test this since the dependency on SomeSession wasn't injected. However, if we use D.I. to inject the dependency in the UserService, the session hangs around for the life of the UserService. If there are multiple services called from the UserController, each could have sessions just hanging around until the UserController is garbage collected.

Any thoughts on how to better manage this? Am I missing something obvious?

Edit

Sorry if I wasn't clear - I understand that I can use Dependency Injection with the Session/Data Context, but then it's being maintained over the life of the Service class. For any longer-running actions/methods (i.e. let's say the service is being called by a batch process), this could lead to a lot of open sessions for no reason other than adding testability.

A: 

The easiest way is to have a Connectionstring that you define in web.config for development and production. For Unittests you define it in app.config of your Testproject.

Malcolm Frexner
+1  A: 

As RichardOD correctly observed, you can't use live database connections for writing unit tests. If you are doing it, then you are integration testing.

I have separate implementations for my repository interface, one real repository, and one fake repository for unit testing. The fake repository works on a generic list instead of a real data context. I am using DI (with Ninject to make things more comfortable, but you can do it just as well by hand) to inject the correct repository.

There are only very few instances in which I am unit testing with real connections, but that's a unit test for my repository class, not for any controller, UI or Business layer objects.

Edit: With the comment you added, I think I now understand what you were actually asking for. Funny you'd ask something about that, since I worked on the very same subject last week :-)

I instantiate the data context inside a very thin wrapper and put the context inside the HttpContext.Current.Items dictionary. This way, the context is global, but only for the current request.

Still, your question's subject is highly misleading. You were asking "where to instantiate a data context for unit testing" and the answer is that you usually don't. My unit tests still operate on fake repositories.

Adrian Grigore
It's ok if you downvote, but it would be nice to explain why this is the case...
Adrian Grigore
Sorry ... I should have responded. Your answer is correct, but I downvoted it because it didn't answer my question. I understand D.I. and how to create a fake repository. The problem is that the context is defined outside the repository, and can be passed around to other Service/Repository classes as well (i.e. so they can participate in the transaction). If we instantiate the context/connection in the Service's c-tor (or inject it), the context's life will be the same as the Service's ... in essence, we extend the connection state well beyond the typical "Using (new context) { ... }".
Jess
Ah, ok. See my edit above...
Adrian Grigore
Jess