以下是本文的一些背景信息。如果你愿意,你可以跳过这个问题:
在这篇优秀的文章(http://ayende.com/Blog/archive/2009/04/28/nhibernate-unit-testing.aspx)中,作者认为“当使用NHibernate时,我们通常只想测试三件事:
1)属性是持久的,
2)级联按预期工作
3)查询返回正确的结果。
- )映射完成&正确的(隐含的)
我认为他继续说SQLite可以而且应该是完成上述所有选择的单元测试工具。应该指出的是,作者似乎是那里经验丰富,技术娴熟的NHib开发人员之一,虽然他在文章中没有明确说明,但他后来在一个问题中暗示该域名可以而且应该处理一些SQLite的缺点。
问题:
如何使用SQLite测试级联关系,特别是考虑到它不检查外键约束。如何测试模型以确保外键约束不会成为db问题。
以下是我为测试级联行为而提出的一些单元测试。该模型只是一个部门,可以有零到多个StaffMembers,级联设置为NONE。
[Test]
public void CascadeSaveIsNone_NewDepartmentWithFetchedStaff_CanSaveDepartment()
{
_newDept.AddStaff(_fetchedStaff);
Assert.That(_newDept.IsTransient(), Is.True);
_reposDept.SaveOrUpdate(_newDept);
_reposDept.DbContext.CommitChanges();
Assert.That(_newDept.IsTransient(), Is.False);
}
[Test]
public void CascadeSaveIsNone_NewDepartmentWithFetchedStaff_CannotSaveNewStaff()
{
_newDept.AddStaff(_newStaff);
Assert.That(_newDept.IsTransient(), Is.True);
Assert.That(_newStaff.IsTransient(), Is.True);
_reposDept.SaveOrUpdate(_newDept);
_reposDept.DbContext.CommitChanges();
Assert.That(_newDept.IsTransient(), Is.False);
Assert.That(_newStaff.IsTransient(), Is.True);
}
[Test]
public void CascadeDeleteIsNone_FetchedDepartmentWithFetchedStaff_Error()
{
_fetchedDept.AddStaff(_fetchedStaff);
_reposDept.SaveOrUpdate(_fetchedDept);
_reposStaff.DbContext.CommitChanges();
_reposDept.Delete(_fetchedDept);
var ex = Assert.Throws<GenericADOException>(() => _reposDept.DbContext.CommitChanges());
Console.WriteLine(ex.Message);
Assert.That(ex.Message, Text.Contains("could not delete:"));
Console.WriteLine(ex.InnerException.Message);
Assert.That(ex.InnerException.Message, Text.Contains("The DELETE statement conflicted with the REFERENCE constraint"));
}
[Test]
public void Nullable_NewDepartmentWithNoStaff_CanSaveDepartment()
{
Assert.That(_newDept.Staff.Count(), Is.EqualTo(0));
var fetched = _reposDept.SaveOrUpdate(_newDept);
Assert.That(fetched.IsTransient(), Is.EqualTo(false));
Assert.That(fetched.Staff.Count(), Is.EqualTo(0));
}
第三个测试“.._ FetchedDepartmentWithFetchedStaff_Error”对Sql Server起作用,但对SQLite不起作用,因为后者不检查外键约束。
以下是关系另一方面的测试;一个StaffMember可以有一个部门,级联设置为NONE。
[Test]
public void CascadeSaveIsNone_NewStaffWithFetchedDepartment_CanSaveStaff()
{
_newStaff.Department = _fetchedDept;
_reposStaff.SaveOrUpdate(_newStaff);
_reposStaff.DbContext.CommitChanges();
Assert.That(_newStaff.Id, Is.GreaterThan(0));
}
[Test]
public void CascadeSaveIsNone_NewStaffWithNewDepartment_Error()
{
_newStaff.Department = _newDept;
Assert.That(_newStaff.IsTransient(), Is.True);
var ex = Assert.Throws<PropertyValueException>(() => _reposStaff.SaveOrUpdate(_newStaff));
Console.WriteLine(ex.Message);
Assert.That(ex.Message, Text.Contains("not-null property references a null or transient value"));
}
[Test]
public void CascadeDeleteIsNone_FetchedStaffWithFetchedDepartment_DeletesTheStaff_DoesNotDeleteTheDepartment()
{
_newStaff.Department = _fetchedDept;
_reposStaff.SaveOrUpdate(_newStaff);
_reposStaff.DbContext.CommitChanges();
_reposStaff.Delete(_newStaff);
Assert.That(_reposStaff.Get(_newStaff.Id), Is.Null);
Assert.That(_reposDept.Get(_fetchedDept.Id), Is.EqualTo(_fetchedDept));
}
[Test]
public void NotNullable_NewStaffWithUnknownDepartment_Error()
{
var noDept = new Department("no department");
_newStaff.Department = noDept;
var ex = Assert.Throws<PropertyValueException>(() => _reposStaff.SaveOrUpdate(_newStaff));
Console.WriteLine(ex.Message);
Assert.That(ex.Message, Text.Contains("not-null property references a null or transient"));
}
[Test]
public void NotNullable_NewStaffWithNullDepartment_Error()
{
var noDept = new Department("no department");
_newStaff.Department = noDept;
var ex = Assert.Throws<PropertyValueException>(() => _reposStaff.SaveOrUpdate(_newStaff));
Console.WriteLine(ex.Message);
Assert.That(ex.Message, Text.Contains("not-null property references a null or transient"));
}
这些测试是针对Sql Server和SQLite进行的。我可以信任SQLite测试吗?这些值得测试吗?
干杯,
Berryl
答案 0 :(得分:3)
据我所知,这篇文章是关于测试NHibernate Mapping的。在我看来,这与db相关的问题无关,而是测试你在映射中设置的nhibernate属性。没有必要断言无法创建无效数据:您只需要证明您的代码创建了所需的结果和/或检查您要检查的内容。您可以测试级联,级联删除和删除孤立。在使用sqlite的测试中,无论你想要什么样的方式。但是第三次测试试图测试约束,这并不是nhibernate所担心的。
如果你想测试你的Db约束,你应该确实使用你的生产数据库,而不是sqlite。您可以使用或不使用hibernate来执行此操作,但这与您的映射无关。 另一方面,如果您真的想要使用SQLite进行外键测试,那么您可以尝试使用此foreign_key_trigger_generator。我没有尝试,但它似乎生成before-insert-triggers,以确保引用的Pk的存在。 也许你可以写这个工具有用的评论。