考虑到大多数现实世界的应用程序在实体之间都有相当复杂的关系,测试单个类映射有多大价值?似乎真正有价值的是,NHibernate测试应该围绕检索、持久化和删除整个对象图,从聚合根级别开始(即Customer-->Order-->OrderDetails)。但是,如果我走上这条路,我似乎必须在对象树中的每一个可以想象的级别上测试CRUD操作,以验证"整体"是否按预期工作;导致测试爆炸:
- 删除客户
- 删除订单
- 删除订单项
- 插入客户
- 插入订单
- 插入订单项
所以,除非我错过了什么,否则我的选择是:
- 为每个类/映射编写一个fixture套件
- 优点:编写CRUD操作更简单
- 缺点:试验值降低,因为它们不能保证整个骨料根部正在正确地持久化
- 为每个对象绘制一个夹具套件图
- 缺点:测试更难编写/测试场景爆炸
- 优点:更高的测试价值,因为它们从应用程序的角度测试持久性(即针对统一/集成对象图测试突变)
如果相关的话,我使用NHibernate.Mapping.ByCode
ConventionModelMapper来使用约定生成映射。
是的,当测试我的映射是否按预期工作时,我在类级别进行测试,并测试每个单独的类关系。
例如,如果我有一个包含Order对象列表的Customer对象,我会为我的Customer对象编写集成测试,以确保我可以对该对象执行所有CRUD操作。然后,我将为Customer对象所具有的所有关系编写测试,例如具有Orders、Addresses等列表。这些测试将涵盖级联插入/更新/删除以及在查询中急切地获取这些子集合的能力。
因此,尽管我在类级别进行测试,因为我正在测试每个类的所有关系,但只要我在每个映射类的每个测试中继续这种测试行为,我就在技术上测试整个对象图。
更新(添加简要示例):
public class Customer
{
public int CustomerId { get; set; }
public string CompanyName { get; set; }
public IList<Address> Addresses { get; set; }
public IList<Order> Orders { get; set; }
}
public class Address
{
public int AddressId { get; set; }
}
public class Order
{
public int OrderId { get; set; }
public string Status { get; set; }
public IList<OrderDetail> OrderDetails { get; set; }
}
public class OrderDetail
{
public int OrderDetailId { get; set; }
public string City { get; set; }
}
[TestFixture]
public class CustomerMappingTests
{
private ISession session;
[SetUp]
public void SetUp()
{
session = UnitOfWork.Current.GetSession();
}
[TearDown]
public void TearDown()
{
session.Dispose();
}
[Test]
public void CanGetCustomer()
{
// Arrange
const int customerId = 1;
// Act
var customer = session.Query<Customer>()
.Where( x => x.CustomerId == customerId )
.FirstOrDefault();
// Assert
Assert.NotNull( customer );
Assert.That( customer.CustomerId == customerId );
}
[Test]
public void CanGetCustomerAddresses()
{
// Arrange
const int customerId = 1;
// Act
var customer = session.Query<Customer>()
.Where( x => x.CustomerId == customerId )
.Fetch( x => x.Addresses )
.FirstOrDefault();
// Assert
Assert.NotNull( customer.Addresses.Count > 0 );
}
[Test]
public void CanGetCustomerOrders()
{
// Arrange
const int customerId = 1;
// Act
var customer = session.Query<Customer>()
.Where( x => x.CustomerId == customerId )
.Fetch( x => x.Orders )
.FirstOrDefault();
// Assert
Assert.NotNull( customer.Orders.Count > 0 );
}
[Test]
public void CanSaveCustomer()
{
// Arrange
const string companyName = "SnapShot Corporation";
var customer = new Customer { CompanyName = companyName };
// Act
session.Save( customer );
session.Flush(); // Update the database right away
session.Clear(); // Clear cache
var customer2 = session.Query<Customer>()
.Where( x => x.CompanyName == companyName )
.FirstOrDefault();
// Assert
Assert.NotNull( customer2 );
Assert.That( customer2.CompanyName == companyName );
}
}