I'm working on a CRUD testing class because I got tired of duplicating the same test patterns when validating my NHibernate mappings.
I've refactored the code and have reached the point where everything is working the way I envisioned it with one glaring irritation. Everything is based on strings which are used by reflection methods to call the appropriate repository methods and get the values of the corresponding properties like entity Id's.
This works but I'm sure I don't need to go into the evils of using strings for such things.
So I started to work with Linq. I'm not a heavy Linq user and the following code has me utterly baffled.
It works almost perfectly (I'll get to the almost in a second) and I'm very happy it works but I would really love to know why.
[Test]
public void TestCanUseTesterWithLinqSecondEffort()
{
IRepositoryTestContextManager contextManager = new NHRepositoryTestContextManager();
contextManager.SetUpRepositoryContextAndSchema();
TestInsertMethodWithLinq<NHClientRepository, Client>((x, y) => x.InsertClient(y), _newClient);
contextManager.ResetRepositoryContext();
Client retrievedClient = TestRetrieveMethodWithLinq<NHClientRepository, Client, string>((clientRepository, publicId) => clientRepository.GetClient(publicId), client => client.PublicId, _newClient);
contextManager.TearDownRepositoryContext();
Assert.IsNotNull(retrievedClient);
Assert.AreNotSame(_newClient, retrievedClient);
Assert.AreEqual(_newClient.Id, retrievedClient.Id);
Assert.AreEqual(_newClient.PublicId, retrievedClient.PublicId);
Assert.AreEqual(_newClient.Name, retrievedClient.Name);
}
private void TestInsertMethodWithLinq<TRepositoryType, TEntityType>(Action<TRepositoryType, TEntityType> insertMethod, TEntityType entity)
where TRepositoryType : class, new()
{
insertMethod.Invoke(new TRepositoryType(), entity);
}
private TEntityType TestRetrieveMethodWithLinq<TRepositoryType, TEntityType, TArgumentType>(Func<TRepositoryType, TArgumentType, TEntityType> retrieveMethod, Func<TEntityType, TArgumentType> paramValue, TEntityType theEntity)
where TRepositoryType : class, new()
{
return retrieveMethod.Invoke(new TRepositoryType(), paramValue(theEntity));
}
Specifically I'm talking about the two invoked delegates (I know one does not have to call invoke to use the delegate. I included it for clarification). How does the compiler transform the Linq expressions so that the correct methods are called on a newly instantiated class, in this case the TRepositoryTypes?
Regarding the almost in "almost perfectly", if there is an exception during the processing of the invoked method, the exception is swallowed. Don't know why that is either but I can already see a scenario where the tests are not complete and a problem is missed because the exceptions are swallowed.
Chew on that. Thanks in advance.