views:

72

answers:

2

Hi Guys,

Realize this may sound like a broad question - so let me clarify. I have a Repository exposed via an interface, with two concrete implementations - a MockRepository and a EntityFrameworkRepository.

Now, i have a Unit-Test project for which all tests can be run against either repository, via flicking over a line in [TestInitialize].

My question is basically "How should i write the tests".

Here's what i have:

C reate

// Arrange.
var foo = new Foo { .. };

// Act
Repository.Add(foo);
UnitOfWork.Commit();

// Assert
Assert.IsTrue(foo.Id > 0);

R etrieve

// Arrange.
var fooToGet = 1;

// Act
var foo = Repository.FindSingle(fooToGet);

// Assert
Assert.IsNotNull(foo);
Assert.AreEqual(foo.Id, fooToGet);

U pdate

// Arrange.
var fooToGet = 1;
var nameToChangeFooTo = "FooBar";

// Act
var foo = Repository.FindSingle(fooToGet);
foo.Name = nameToChangeFooTo;
UnitOfWork.Commit();
var fooRetrievedAgain = Repository.FindSingle(fooToGet);

// Assert
Assert.IsNotNull(foo);
Assert.AreEqual(fooRetrievedAgain.Id, fooToGet);
Assert.AreEqual(fooRetrievedAgain.Name, nameToChangeFooTo);

D elete

// Arrange.
var fooToGet = 1;

// Act
var foo = Repository.FindSingle(fooToGet);
Repository.Remove(foo);
UnitOfWork.Commit();
var fooRetrievedAgain = Repository.FindSingle(fooToGet);

// Assert
Assert.IsNull(fooRetrievedAgain);

It's working ok, for both the Mock and EF repository, but my main problem is C (Create). I'm not sure how to test an Add operation on my Repository. It doesn't feel right what im doing.

It passes for the EF Repository, but to make it pass in my Mock Repository i had to use reflection to update the ID in the in-memory collection (nasty).

So - can you please share some advice on what are the correct ways to test CRUD operations on the Repository Pattern?

This is an ASP.NET MVC Application, .NET 4, C#, Entity Framework 4 and Unit of Work/Repository Patterns.

Thanks.

EDIT

Just to clarify guys, these are not all the unit-tests i have. I have unit tests for my service layer, as well as business-rule tests.

Both the latter will (and should) fail if my above Repository tests fail. That is the point here, to unit-test the very basic operations of my Repositories. Am i wrong?

A: 

One option is to use an in-memory DB like SqlLite to test the behaviour of your mappings, queries and repositories. This is discussed by Ayende here, though his example uses NHibernate.

Another option which seems to address your immediate concern of setting the Ids of the domain objects is to use test fakes. This is discussed by RhysC here.

martinl
Think your misunderstanding my question. I already have a Mock Repository in place, im asking how can i write tests that should pass against both the Mock and Real Repository. Look at Ayende's test method. That's the info i want (how to write the test properly), not the actual implementation detail.
RPM1984
If the repository doesn't contain any complicated logic and just forwards requests to the underlying store. Then an interaction based test rather than a state based one might be more appropriate. ie mock out the store thats injected into the repo. And assert that certain methods were called on it. Rather than asserting on the value of the domain object id.
martinl
A: 

IMO, your create test should:

  • add an entity to the repository
  • assert it was assigned an ID
  • retrieve the inserted entity using the ID
  • compare the initial entity with the read entity and make sure their properties are same

I've got many unit tests like yours the main difference is that I'm using a deep comparison method to compare object instances. For instance, my U tests look like this:

  • add an entity to the repository
  • retrieve the inserted entity using the ID
  • change some of the entity properties
  • update the entity in the repository
  • retrieve the updated entity using the ID
  • compare the updated entity with the read entity and make sure their properties are same (you can define a specific logic for properties that are not updatable)
vc 74
Interesting. Although your U (Update) also tests an add. Is that really a unit-test? The rest of your U test makes sense, but not the adding of it first. IMO an Update test should involve retrieving an existing item, and then updating it. However your answer (and thoughts) are most welcome. Thanks.
RPM1984
I see your point but if you don't insert the entity, you have to rely on a previous state which could have been created by a ClassInitialize for instance. I really prefer my tests to be atomic. Also, note that I'm not testing anything on the inserted entity.
vc 74
Actually yes that's a great point. Test's should be atomic.
RPM1984