unit testing a database query via nhibernate
我需要为从数据库加载数据的方法创建单元测试。 我正在研究一下单元测试和数据库,大多数文章告诉你应该模拟数据库。 但是,此方法基本上从数据库加载对象,并通过SQL执行一些限制。
因此,我想测试的是实际的数据库查询是否成功,因此我认为不能模拟数据库。
我使用NHibernate作为我的ORM,并且使用
这是我想要进行单元测试的特殊方法:
1 2 3 4 5 6 7 8 9 10 11 12 | 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); } |
过去,当我需要对数据库进行单元测试时,我通常使用SQLite。您基本上在内存中设置SQLite数据库,然后配置您的NHibernate(依赖注入,或者您想要这样做)连接到SQLite而不是您的普通数据库。几乎所有查询都应该能够正确运行。
如果您需要强大的DateTime支持,SQLite可能会让您失望(请参阅Ayende的帖子)。在这种情况下,您可以使用任何嵌入式数据库。我建议设置一个RAMDisk并将嵌入式数据库放在该磁盘上,因此它仍然在内存中运行。
我们使用来自NCommon的IRepository。然后我们使用InMemoryRepository进行单元测试。非常光滑,快速,易于使用。
我个人使用真正的数据库来进行集成测试。我觉得这是最接近真实生产场景的。我们的开发团队目前没有从nhibernate映射生成数据库,因此映射和数据库之间存在一些不一致(比如数据库默认值等)。如果从nhibernate生成模式,SQLLite可能是适合您的路径。但如果你不是我个人觉得最好将这些测试写在真正的数据库上。
我的集成测试将为测试插入必要的数据,并在测试后删除数据。此方法的唯一缺陷是您必须确保在测试结束后删除所有数据,否则可能会影响其他测试。我发现这对我们公司来说是一个可行的解决方案,但它非常有帮助。我们有专门的数据库,仅用于单元测试。
以下是我的一个测试示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | [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(); } } |