2012-08-30 61 views
3

我需要为从数据库加载数据的方法创建单元测试。我正在研究一些单元测试和数据库,大多数文章告诉你应该模拟数据库。但是,此方法基本上从数据库加载对象,并通过SQL执行一些限制。单元测试通过nhibernate查询数据库

因此,我想测试的是,实际的数据库查询工作成功,因此我不认为可以模拟数据库。

我使用NHibernate作为我的ORM,并且使用QueryOver构建查询。由于数据库处于不一致状态,我发现单元测试数据库非常成问题。任何想法/方法如何去做这样的测试?

这是特定的方法,我想单元测试:

public IEnumerable<IArticlePanel> LoadPanelsApplicableToArticle(ArticleModule.IArticle article, Enums.ARTICLE_PANEL_LOCATION location) 
    { 
     CS.General_v3.Util.ContractsUtil.RequiresNotNullable(article, "Article must not be null"); 

     var articleList = Modules.Factories.ArticleFactory.GetAllParentsForAnArticle(article).ToList(); 
     articleList.Add(article); 

     var q = GetQuery(); 
     q = q.WhereRestrictionOn(x => x.Article).IsInG(articleList.ConvertAll<long>(x => ((IBaseDbObject)x).ID)); 
     q = q.Where(x => x.Location == location); 
     return FindAll(q); 
} 
+0

切换到sqlite数据库进行测试。 –

回答

4

在过去,当我需要的单元测试数据库,我通常使用SQLite。你基本上在内存中设置SQLite数据库,然后配置你的NHibernate(依赖注入,或者你想这样做)来连接到SQLite,而不是你的普通数据库。几乎所有的查询都应该能够正确运行。

如果您需要强大的DateTime支持,SQLite可能会让您失望(请参阅Ayende的文章here)。在这种情况下,您可以使用任何嵌入式数据库。我建议设置一个RAMDisk并将嵌入式数据库放置在该磁盘上,这样它仍然在内存中运行。

+0

这种方法的问题是有一些设置,其他值必须在数据库中作为特定的初始化代码等依赖于它们。因此,我需要重新创建一个SQLite从头开始,填充这些设置等。我试着走下这条路线,但时不时维护。 –

+0

如果您的单元测试数据库本身确实非常重要,那么投入一点额外时间来编写SQLite数据库创建和自定义代码通常不是什么大问题。我从来没有遇到过要花一天多时间才能写出初始化数据库所需的所有内容,然后再为所有未来的单元测试完成。如果不值得花那么多时间,那么根本就不值得担心数据层的单元测试。 –

0

我个人使用真正的数据库来做我的集成测试。我觉得这是最接近真实生产场景的。我们的开发团队目前没有从nhibernate映射生成数据库,因此映射和数据库之间存在一些不一致之处(比如数据库默认值等)。如果您从nhibernate生成模式,SQLLite可能是您正确的路径。但是,如果你不是,我个人觉得把这些测试与真实数据库相比较好。

我的集成测试将为测试插入必要的数据并在测试后删除数据。这种方法唯一的缺陷是,您必须确保在测试结束后删除所有数据,否则可能会影响其他测试。我发现这对我们公司来说是一个可行的解决方案,而且它非常有帮助。我们有专用的数据库,仅用于单元测试。

下面是我的测试中的一个例子:

[TestMethod] 
public void Test_NHibernate_Query() 
{ 
    //Create the data in the database necessary to test my nhibernate query 
    CreateDataForUnitTest(); 

    IInventoryRepository target = new InventoryRepository(nhibernateSession); 

    IList<InventoryView> inventoryRecords = target.GetContainerInventory(productId); 

    Assert.AreEqual(1, inventoryRecords.Count); 
} 

[TestCleanup] 
public void CleanUp() 
{ 
    DeleteAll<Order>(); 
    DeleteAll<Company>(); 
} 

public void DeleteAll<T>() where T : Entity 
{ 
    NHibernate.ISession session = SessionFactory.GetCurrentSession(); 

    using (NHibernate.ITransaction tran = session.BeginTransaction()) 
    { 
     IList<T> items = session.CreateCriteria<T>() 
      .List<T>(); 

     foreach (T p in items) 
     { 
      session.Delete(p); 
     } 

     tran.Commit(); 
    } 
} 
+0

这就是我目前的工作方式。但是,有时由于依赖关系,清理并不容易,并使数据库恢复到一致状态。我希望更多地了解目前我是否还没有意识到的选项,但看起来这是最适合我的案例。 –

+0

如果您使用的是mssql,如果该一致状态表示为空,则可能会轻松地将数据库恢复为一致状态。 http://stackoverflow.com/questions/155246/how-do-you-truncate-all-tables-in-a-database-using-tsql我实际上可能会考虑这样做,而不是。 –

0

我们使用IRepository从NCommon。然后我们使用InMemoryRepository进行单元测试。非常光滑,快速且易于使用。