views:

57

answers:

2

Assuming I have a class with a method that takes a System.Linq.Expressions.Expression as a parameter, how much value is there in unit testing it?

public void IList<T> Find(Expression expression)
{
    return someCollection.Where(expression).ToList();
}

Unit testing or mocking these sorts of methods has been a mind-frying experience for me and I'm now at the point where I have to wonder whether it's all just not worth it.

How would I unit test this method using some arbitrary expression like

List<Animal> = myAnimalRepository.Find(x => x.Species == "Cat");
+2  A: 

Why not? - It is part of the public interface of the SUT.

This looks easy to test as well. I generally don;t use mocks unless its absolutely required. I'd write the test like

[Test]
public void Find()
{
  var animalRepository = new AnimalRepository();
  animalRepository.Add( dog ); // create a object to species = dog and other relevant attr
  animalRespository.Add( cat ); // etc. etc..

  var results = animalRepository.Find( a => a.Species == "Cat");

  Assert.That( results.Is.EquivalentTo( new List<Animal> { cat } ) );
}
  1. Arrange: setup SUT so that internal somecollection contains a few known objects - e.g. Add(dog); Add(cat); etc.
  2. Act: invoke the Find method with a condition
  3. Assert: Assert.That( results.Is.EquivalentTo(expected_results)

You can try a couple of query expressions to ensure that the Find method is using it as a Where clause. That should do it.

Gishu
+2  A: 

It is a bit artificial to unit test this, since each LINQ provider is implementation-specific. You might use various different approaches in your test, and it simply won't tell you anything about the real implementation. For example, if it is mocked via LINQ-to-Objects, I could use:

List<Animal> = myAnimalRepository.Find(x => CheckSpecies(x, "Cat"));
...
static bool CheckSpecies(Animal animal, string species) {
    return animal.Species == species;
}

That will work with LINQ-to-Objects... but only with LINQ-to-Objects. Likewise, a UDF usage (or one of the SQL helper methods) will work in LINQ-to-SQL but not Entity Framework.

I've reached the conclusion that only integration tests are useful for this scenario, so no; mocking isn't very helpful here. It will give you a warm happy feeling that you've done something useful, but ultimately it doesn't test that what you write in your app will work.

An even better approach, IMO, is not to expose such over your repository interface. If you limit the LINQ queries to your data-layer you remove the risk and now you are testing (/mocking) a pure, predicatable interface.

I discuss this more here.

Marc Gravell