views:

451

answers:

2

If I have the following domain object:

public class Customer
{
    public virtual Guid Id { get; set; }
    public virtual string Name { get; set; }
    public virtual ISet<Order> Orders { get; set; }

    public Customer()
    {
        Orders = new HashedSet<Order>();
    }

    public virtual void AddOrder(Order order)
    {
        order.Customer = this;
        Orders.Add(order);
    }
}

with the following NHibernate mapping:

<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" namespace="Examples" assembly="Examples">
  <class name="Customer">
      <id name="Id">
        <generator class="guid.comb" />
      </id>
      <property name="Name" length="50"/>
      <set name="Orders" table="CustomerOrder" cascade="all-delete-orphan" lazy="true">
        <key column="CustomerId"/>
        <many-to-many class="Order" column="OrderId"/>
      </set>
  </class>
</hibernate-mapping>

Is there any value in this test?

[Test]
public Save_NameWritten_SameNameIsReadback()
{
    var expected = new Customer { Name = "Fred Quimby" };
    _repo.Save(c);
    var actual = _repo.Find(expected.Id);
    Assert.AreEqual(expected.Name, actual.Name);
}

Do folks commonly test their persistence layer like this? Making sure that each field is persisted individually? I'm honestly not sure what best practice is for something like this. I can see testing something with long strings and parent/child relationships - but what about integers and dates? Is this overkill?

I'm just talking about the persistence layer here, not the business logic in the domain layer. For that, I would mock the repository, whereas here I'm verifying that the repository actually saved the thing that I told it to save. What if someone forgets to map a field, or they have a bogus string length in the mapping?

Are there any tools to automatically generate these kinds of tests in .NET? Or is that "bad"?

+3  A: 

if you make sure that you are saving and fetching data in a different sessions then you can effectively make sure that your mappings are correct - this is the value.

the best for that would be to use in memory database and something like PersistenceSpecification (here is a post about it) from fluent NHibernate which can insert and select data for you in a different sessions.

Marek Blotny
A: 

These tests have a great deal of value as they are ultimately the only way to verify that you really can talk to the database. Once you have validated that you have a working repository, you can mock out the calls to the repository in other unit tests, as you mentioned.

Be careful about using an in memory database exclusively - as you need to know that your target database works correctly. Also be careful about session usage in these tests. If you really want to hit the database when you load, make sure that Save and Find take place ini different sessions.

As few things which you could verify using these wired up database tests:

  • Boundary lengths for strings
  • Lazy loading. You can use detached sessions to verify that you get a lazy load exception for a connected object which you do not want to eagerly load and vice versa. This is important for more complex domain hierarchies when someone inadvertently adds a navigational path through the object graph which causes the entire database to be loaded in.
  • Foreign keys and unique constraints.
  • Efficiency of search calls to the repository with large datasets.
Stuart Caborn