C# 在DDD/TDD应用程序中测试持久层

C# 在DDD/TDD应用程序中测试持久层,c#,nhibernate,tdd,domain-driven-design,C#,Nhibernate,Tdd,Domain Driven Design,如果我有以下域对象: 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 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);
    }
}
人们通常这样测试他们的持久层吗?确保每个字段都是单独保存的?老实说,我不确定这种事情的最佳实践是什么。我可以看到用长字符串和父/子关系测试一些东西,但是整数和日期呢?这是不是太过分了

这里我只讨论持久层,而不是域层中的业务逻辑。为此,我将模拟存储库,而在这里,我将验证存储库是否确实保存了我告诉它要保存的内容。如果有人忘记映射字段,或者映射中有伪造的字符串长度,该怎么办


有没有工具可以在.NET中自动生成这些类型的测试?或者这是“错误的”

如果您确保在不同的会话中保存和获取数据,那么您可以有效地确保映射是正确的-这就是值


最好的方法是使用内存数据库和fluent NHibernate提供的PersistenceSpecification(这里是一个关于它的介绍),它可以在不同的会话中为您插入和选择数据。

这些测试有很大的价值,因为它们最终是验证您是否真的可以与数据库对话的唯一方法。一旦您验证了您有一个工作的存储库,您就可以在其他单元测试中模拟对存储库的调用,正如您所提到的

在以独占方式使用内存中数据库时要小心,因为您需要知道目标数据库工作正常。在这些测试中还要注意会话的使用。如果您确实想在加载时访问数据库,请确保保存和查找在不同的会话中进行

使用这些连接数据库测试,您可以验证的内容不多:

  • 字符串的边界长度
  • 延迟加载。您可以使用分离的会话来验证您是否获得了一个连接对象的延迟加载异常,而您不想急切地加载该对象,反之亦然。这对于更复杂的域层次结构非常重要,因为当有人无意中添加了通过对象图的导航路径,从而导致加载整个数据库时
  • 外键和唯一约束
  • 使用大型数据集对存储库进行搜索调用的效率
<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>
[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);
}