Hi Geo,
I'll explain what I'm doing, why and how much milage I get out it.
First, I'm doing exactly what you are doing, regarding your repositories. Despite some namespace differences, this is what I also do:
- MyProject.Repositories.IUserRepository
- MyProject.Repositories.Fake.UserRepository
- MyProject.Repositories.SqlServer.UserRepository
With my fake UserRepository, I also just create and populate a private IEnumerable<User>
collection (which is a List<User>
). Why do I have this? I use this repository for my initial day to day development (because it's fast -> no db access == quick!). Then i swap over the fake respitories for the sql repositories (ie chage my dependency injection (oooohhh!)). This is why this class/namespace exists, as opposed to using Mocks in my unit test for 'fake' stuff. (That happens, but under different circumstances).
With my sql server UserRepository, I use LinqToSql. With regards to you question, it's irrelivant that I'm using LinqToSql ... it could be any other database wrapper. The important thing here is that there's a 3rd party something which i'm integrating with.
Ok, so from here, I need to make sure of two things
- The fake UserRepostiory works
- The sql server UserRepository works.
First up, most people don't create a unit test for a fake thing. It's a fake piece of turd, so why waste the energy? True --- except that I use that fake piece of turd in my day to day development (refer to my blarg about this, above). So i quickly whip up a few basic unit tests. NOTE: In my eyes these are unit tests, even though they are repository
classes. Why? They aren't intergrating with a 3rd party/infrastructure.
Next (finally I get to the point), I do a seperate test class which is an Intergration Test. This is a unit test that will intergrate with something outside of the system. It could be the real Twitter api. It could be the real S3 Amazon api. Notice i used the word real. That's the key, here. I'm intergrating with a real service OUTSIDE of mine. As such -> it's slow. Anytime i need to leave my computer for some data, it's called intergrating and you automatically assume (and expect) it to be slow.
So here, i'm intergrating with a Database.
(Nae sayers, please don't Troll this with cheeky suggestions that you have the database on the same computer ... you're leaving your APPLICATION 'world').
Wow. this is some War-n-Peace novel .. time for some hard action, cock slappin code.
Lets bring it!
namespace MyProject.Tests.Repositories.SqlServer
{
// ReSharper disable InconsistentNaming
[TestClass]
public class UserRepositoryTests : TestBase
{
[ClassInitialize]
public static void ClassInitialize(TestContext testContext)
{
// Arrange.
// NOTE: this method is inherited from the TestBase abstract class.
// Eg. protected IUserRepository =
// new MyProject.Respositories.SqlServer
// .UserRespository(connectionString);
InitializeSqlServerTestData();
}
[TestMethod]
public void GetFirst20UsersSuccess()
{
// Act.
var users = _users.GetUsers()
.Take(20)
.ToList();
// Assert.
Assert.IsNotNull(users);
Assert.IsTrue(users.Count() > 0);
}
}
}
Ok, lets run through this puppy.
First up, this is using Microsoft Unit Testing - built into VS2010 Beta2 or with the Team Foundation edition of VS2008 (or whatever that version is ... i just install the copy our work has purchased).
Second, whenever the class is first initialized (be it one test or many), it creates the context
. In my case, my Sql Server UserRepository which will use a LinqToSql context. (Yours will be an EF context). This is the Arrange part of TDD.
Third, i call the method -> this is the Act part of TDD.
Last, I check if i got back what i expected -> this is the Assert part of TDD.
What about updating the DB?
Just follow the same pattern except you might want to wrap your calling code in a transaction and the roll it back. Otherwise u might get 100's of rows of data which could possibly be the same. Downside to this? Any identity
fields will not have all nice and pretty numbering sequence (becuase the rollback will 'use' that number). Doesn't make sence? don't worry. that's an advanced tip i thought i'd throw in to test you out, but it means diddly squat for this hellishly long post.
so .. er.. yeah. that's what i do. Don't know if the Gods of Programming, on these forums, will flip and throw mud my way but I sorta like it and I'm hoping it might help ya.
HTH.