简体   繁体   English

通过nhibernate对数据库查询进行单元测试

[英]unit testing a database query via nhibernate

I need to create a unit test for a method which loads data from the database. 我需要为从数据库加载数据的方法创建单元测试。 I was researching a bit into unit testing and databases, and most articles tell you that you should mock the database. 我正在研究一下单元测试和数据库,大多数文章告诉你应该模拟数据库。 However, this method basically loads objects from a database, and performs some restrictions via SQL. 但是,此方法基本上从数据库加载对象,并通过SQL执行一些限制。

Therefore, what I want to test is that the actual database query is working successful, hence I don't think one can mock the database. 因此,我想测试的是实际的数据库查询是否成功,因此我认为不能模拟数据库。

I am using NHibernate as my ORM, and the query is being built using QueryOver . 我使用NHibernate作为我的ORM,并且使用QueryOver构建查询。 I find it extremely problematic to unit-test databases, due to the database being in an inconsistent state. 由于数据库处于不一致状态,我发现单元测试数据库非常有问题。 Any ideas / methods how one would go about doing such a test? 任何想法/方法如何进行这样的测试?

This is the particular method I would like to unit-test: 这是我想要进行单元测试的特殊方法:

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);
 }

In the past, when I've needed to unit test a database, I have usually used SQLite . 过去,当我需要对数据库进行单元测试时,我通常使用SQLite You basically set up the SQLite database in memory, then configure your NHibernate (dependency injection, or however you want to do it) to connect to SQLite instead of your normal database. 您基本上在内存中设置SQLite数据库,然后配置您的NHibernate(依赖注入,或者您想要这样做)连接到SQLite而不是您的普通数据库。 Almost all queries should be able to run correctly. 几乎所有查询都应该能够正确运行。

If you need strong DateTime support, SQLite will probably let you down (see Ayende's post about that here ). 如果你需要强大的DateTime支持,SQLite的将可能让你失望(见Ayende的有关职务这里 )。 In that case, you can use any of the embedded databases. 在这种情况下,您可以使用任何嵌入式数据库。 I would recommend setting up a RAMDisk and place the embedded database on that disk, so it still runs in-memory. 我建议设置一个RAMDisk并将嵌入式数据库放在该磁盘上,因此它仍然在内存中运行。

Personally I have used real databases to do my integration tests. 我个人使用真正的数据库来进行集成测试。 I feel that this is the closest to real production scenarios as possible. 我觉得这是最接近真实生产场景的。 Our development team is not currently generating the database from the nhibernate mappings so there were some inconsistencies between the mappings and the database (things like database defaults etc). 我们的开发团队目前没有从nhibernate映射生成数据库,因此映射和数据库之间存在一些不一致(比如数据库默认值等)。 If you are generating the schema from nhibernate SQLLite may be the right path for you. 如果从nhibernate生成模式,SQLLite可能是适合您的路径。 But if you aren't I personally feel that it's better to write these tests against the real database. 但如果你不是我个人觉得最好将这些测试写在真正的数据库上。

My integration tests will insert the necessary data for the tests and delete the data after the test. 我的集成测试将为测试插入必要的数据,并在测试后删除数据。 The only pitfall to this method is that you have to make sure you delete all the data after your test is over otherwise it could affect other tests. 此方法的唯一缺陷是您必须确保在测试结束后删除所有数据,否则可能会影响其他测试。 I've found this to be a viable solution for our company though and it's been extremely helpful. 我发现这对我们公司来说是一个可行的解决方案,但它非常有帮助。 We have a dedicated database only used for unit testing. 我们有专门的数据库,仅用于单元测试。

Below is an example of one of my tests: 以下是我的一个测试示例:

[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();
    }
}

We use IRepository from NCommon. 我们使用来自NCommon的IRepository。 Then we use InMemoryRepository for unit testing. 然后我们使用InMemoryRepository进行单元测试。 Very slick, fast, and easy to use. 非常光滑,快速,易于使用。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM