The FluentNHibernate (source on github) includes extensive unit tests, one of which, PersistenceSpecificationTester, performs detailed tests using PersistenceSpecification<T> to validate class maps.
For the spike, I've tried to simplify this down as much as possible, working with a single entity, a base class (DomainEntity, to handle equality) and a static utility method for building an ISessionSource containing any entity class.
Use the following to build your class mapping test:
1) Create a domain model with two entities:
- Product
- DomainEntity, a common base class for handling identity/equality
Product.cs
public class Product : DomainEntity
{
// Location is an immutable value object containing Aisle and Shelf properties;
// included to demonstrate FluentNHibernate's mapping of an entity component
public Location Location { get; set; }
public decimal Price { get; set; }
public string Name { get; set; }
}
DomainEntity.cs
public class DomainEntity
{
public int Id { get; set; }
public override bool Equals(object obj)
{
var other = obj as DomainEntity;
return other != null
&& other.Id > 0
&& other.Id.Equals(this.Id);
}
public override int GetHashCode()
{
return this.Id.GetHashCode();
}
}
2) Create a mapping file using FluentNHibernate's ClassMap<T>.
ProductMap.cs
public class ProductMap : ClassMap<Product>
{
public ProductMap()
{
Id(x => x.Id);
Map(x => x.Name);
Map(x => x.Price);
Component(x => x.Location, m =>
{
m.Map(x => x.Aisle);
m.Map(x => x.Shelf);
});
}
}
3) Create a static class/method that accepts any domain entity class (i.e. which extends DomainEntity) and returns a mock in-memory NHibernate session containing an instance of the entity (which we will use next to test the mappings).
FluentNHibernateMappingTester.cs
using FluentNHibernate;
using Gaddzeit.Spike.Domain.Entities;
using NHibernate;
using Rhino.Mocks;
namespace Gaddzeit.Spike.Tests.Unit
{
public static class FluentNHibernateMappingTester
{
public static ISessionSource GetNHibernateSessionWithWrappedEntity<T>(T tMappedEntityWithinSession) where T : DomainEntity
{
var transaction = MockRepository.GenerateStub();
var session = MockRepository.GenerateStub();
session.Stub(s => s.BeginTransaction()).Return(transaction);
session.Stub(s => s.Get<T>(null)).IgnoreArguments().Return(tMappedEntityWithinSession);
session.Stub(s => s.GetIdentifier(tMappedEntityWithinSession)).Return(tMappedEntityWithinSession.Id);
var sessionSource = MockRepository.GenerateStub();
sessionSource.Stub(ss => ss.CreateSession()).Return(session);
return sessionSource;
}
}
}
4. To test the entity mapping, you need a comparer class that implements IEqualityComparer, and can test both the equality of the entity itself, as well as the equality of any of its properties.
ProductComparer.cs
public class ProductComparer : IEqualityComparer
{
public bool Equals(object x, object y)
{
if (x is Product && y is Product)
return ((Product)x).Id == ((Product)y).Id;
if (x is string && y is string)
return x.ToString().Equals(y.ToString());
if (x is decimal && y is decimal)
return Convert.ToDecimal(x).Equals(Convert.ToDecimal(y));
throw new EqualityComparerUnhandledComparisonException();
}
public int GetHashCode(object obj)
{
if (obj is Product)
return ((Product) obj).GetHashCode();
if (obj is string)
return obj.ToString().GetHashCode();
if (obj is decimal)
return Convert.ToDecimal(obj).GetHashCode();
throw new EqualityComparerUnhandledComparisonException();
}
}
5. Finally: create a test for the mapping of Product, which calls to the static method to setup the Product instance in the mocked in-memory NHibernate Session (returned as ISessionSource), and then passes ISessionSource and the above ProductMapper into PersistenceSpecification
ProductMappingTests.cs
using FluentNHibernate.Testing;
using Gaddzeit.Spike.Domain.DomainServices;
using Gaddzeit.Spike.Domain.Entities;
using NUnit.Framework;
namespace Gaddzeit.Spike.Tests.Unit
{
[TestFixture]
public class ProductMappingTests
{
[Test]
public void NameProperty_IsMapped_Correctly()
{
var product = new Product
{
Id = 35,
Location = new Location(35, 27),
Name = "Hammer",
Price = 35.99M
};
var identicalProduct = new Product
{
Id = 35,
Location = new Location(35, 27),
Name = "Hammer",
Price = 35.99M
};
var sessionSource = FluentNHibernateMappingTester.GetNHibernateSessionWithWrappedEntity(identicalProduct);
var spec = new PersistenceSpecification(sessionSource, new ProductComparer());
spec.CheckProperty(p => p.Name, product.Name).VerifyTheMappings();
}
}
}
That's it! Your test should pass, and you have verified that your entity is mapped correctly, without setting up a real connection to a database.
No comments:
Post a Comment