The Inquisitive Coder – Davy Brion's Blog

Trying to walk that thin line between intelligence and ignorance

Testing CRUD Operations With NHibernate

Posted by Davy Brion on December 7th, 2009

I was asked to show how you can easily do CRUD tests, so here’s a base class that makes it very easy

    public abstract class CrudTest<TEntity, TId> : NHibernateTest

        where TEntity : IHaveAnId<TId>

    {

        [Test]

        public virtual void SelectQueryWorks()

        {

            session.CreateCriteria(typeof(TEntity)).SetMaxResults(5).List();

        }

 

        [Test]

        public virtual void AddEntity_EntityWasAdded()

        {

            var entity = BuildEntity();

 

            InsertEntity(entity);

 

            session.Evict(entity);

 

            var reloadedEntity = session.Get<TEntity>(entity.Id);

 

            Assert.IsNotNull(reloadedEntity);

            AssertAreEqual(entity, reloadedEntity);

            AssertValidId(reloadedEntity);

        }

 

        [Test]

        public virtual void UpdateEntity_EntityWasUpdated()

        {

            var entity = BuildEntity();

 

            InsertEntity(entity);

            ModifyEntity(entity);

            UpdateEntity(entity);

 

            session.Evict(entity);

 

            var reloadedEntity = session.Get<TEntity>(entity.Id);

            Assert.IsNotNull(reloadedEntity);

            AssertAreEqual(entity, reloadedEntity);

        }

 

        [Test]

        public virtual void DeleteEntity_EntityWasDeleted()

        {

            var entity = BuildEntity();

 

            InsertEntity(entity);

            DeleteEntity(entity);

 

            Assert.IsNull(session.Get<TEntity>(entity.Id));

        }

 

        protected virtual void InsertEntity(TEntity entity)

        {

            session.Save(entity);

            session.Flush();

        }

 

        protected virtual void UpdateEntity(TEntity entity)

        {

            session.Update(entity);

            session.Flush();

        }

 

        protected virtual void DeleteEntity(TEntity entity)

        {

            session.Delete(entity);

            session.Flush();

        }

 

        protected abstract TEntity BuildEntity();

        protected abstract void ModifyEntity(TEntity entity);

        protected abstract void AssertAreEqual(TEntity expectedEntity, TEntity actualEntity);

        protected abstract void AssertValidId(TEntity entity);

    }

 

Simply inherit from this class, implement the BuildEntity, ModifyEntity, AssertAreEqual and AssertValidId methods and that’s it.  Those methods are usually pretty simple.  In BuildEntity you just create an unpersisted entity and assign values to the properties, in ModifyEntity you modify the properties, and in AssertAreEqual you compare the properties of both instances.  In AssertValidId, you make sure that the ID value is ok (depending on your identifier strategy).

This is good for regular CRUD operations, though we typically add extra tests when we want to test cascades or one-to-many associations mapped with inverse=”true”.

13 Responses to “Testing CRUD Operations With NHibernate”

  1. Grant Palin Says:

    Just came from your previous post. This is a nice follow-up, another worthy of bookmarking!

    Supposing that you follow the multi-layer approach to your project, this code would be used in testing persistence with NHibernate, right? So higher-level code which would normally interact with NH-backed repositories would actually interact with fake version of such, just so you can keep the different test types separate…Am I right??

  2. Davy Brion Says:

    @Grant

    the class shown in this post is only useful to test the correctness of your mappings by making sure that CRUD operations work for all entities. and as mentioned in the previous post, we also write tests for each specific custom query that we write.

    our higher level code (the one that indees communicates with repositories for all NH-related tasks) is always tested with mocked repositories.

  3. Reflective Perspective - Chris Alcock » The Morning Brew #493 Says:

    [...] Testing CRUD Operations With NHibernate – Davy Brion shares a simple base class which provides the groundwork for testing Create Read Update and Delete functionality of NHibernate types [...]

  4. Ere Thrice the Sun Done Salutation to the Dawn « Search And Destroy Says:

    [...] by kilfour on January 15, 2010 A while ago davy brion posted a nice base class for nhbirnate crud tests, which i eagerly [...]

  5. Morten Jacobsen Says:

    Great article, I’m trying to incorporate your ideas into my own project.. I have two questions though (this may seem stupid, but I’m still new to TDD and I’m sorta forcing myself to write tests and learn it properly):

    Say you have a CustomerTests class that inherits your baseclass.. Because customers have orders we need to test add/remove orders methods.. Would you then override the buildEntity etc. to also create orders so you can manipulate those or would you have the order creation logic separate (i.e. call BuildEntity() to get a customer, then create and add order to it)?

    Also, when you reload your customer, how much detail would you go into to check that the order was there? Would you simply check that order count has increased by one or would you check the details of the order also?

    Regards,
    Morten

  6. Davy Brion Says:

    @Morten

    i would test the add/remove methods in separate test methods and leave the base methods in this test fixture stricture for the entity itself, and many-to-ones

    but one-to-many’s or many-to-many’s deserver their own test methods :)

    as for what to check on => i’d go for the count plus an ID check if you also have specific tests for the orders, or if you don’t have those, i’d do a complete check

  7. Morten Jacobsen Says:

    Davy,

    I’ve slightly modified your baseclasses, but whenever i try to run the tests, i get the following exception:

    TypeInitializationException: The type initializer for ‘NHibernate.ByteCode.Castle.ProxyFactory’ threw an exception. Could not load file or assembly ‘Castle.DynamicProxy2, Version=2.1.0.0, Culture=neutral, PublicKeyToken=407dd0808d44fbdc’ or one of its dependencies. The located assembly’s manifest definition does not match the assembly reference. (Exception from HRESULT: 0×80131040)

    Any ideas?

    My changes mainly concerns the use of ISession directly instead of the ActiveSessionManager and UnitOfWork.. Also, I have a TestFixtureSetUp method that configures NHibernate and builds the sessionfactory (it is here i get the exception)..

  8. Morten Jacobsen Says:

    I forgot to point out that the assemblies are indeed referenced in the project and i have tried readding them to no avail..

  9. Davy Brion Says:

    @Morten

    did you include a reference to Castle.DynamicProxy2 in your test project?

  10. Davy Brion Says:

    @Morten

    sorry, missed the last comment

    did you also include Castle.Core? are you sure that you have the correct versions? maybe your NHibernate.ByteCode.Castle.ProxyFactory was built against a different version of DynamicProxy2 than the one you included.

  11. Morten Jacobsen Says:

    Davy,

    Yes i’ve tried with and without Castle.Core.. How do I check which version nhibernate requires? I downloaded the lastest DynamicProxy2 and the lastest Nhibernate releases..

  12. Davy Brion Says:

    @Morten

    your NHibernate assemblies were compiled against Castle 2.1.0.0 (you can tell from the version number listed in the exception message)

  13. Morten Jacobsen Says:

    Aha, I was misinterpreting the error message.. It seems the dll I have is DynamicProxy2 2.1.1.. Two months of vacation seems to have affected my thinking :) .. Anyways, thanks for the help :)

Leave a Reply

XHTML: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>