1

我正在尝试使用 .net mvc 4 和流利的 nhibernate 创建应用程序。

我创建了ProductsFacade负责获取数据并将数据插入数据库的程序。方法GetProductsByPageAndCategory用于从数据库中获取记录页。我想编写单元测试来检查分页是否正常工作。

这很难做到,因为分页必须在单个QueryOver查询中完成。我不能只编写单独的方法来获取数据,模拟它并编写单独的分页方法。所以我需要模拟数据库。我使用 moq 工具进行模拟。

也许有人可以就如何做到这一点提供一些提示?或任何其他替代方法如何解决我的问题?

public class ProductFacade {
    //...

    public virtual IList<Product> GetProductsByPageAndCategory(
        string category,
        int pageNumber,
        int pageSize)
    {
        //IList<Product> products = ;
        var productsQuery = _session.QueryOver<Product>();
        if (category != null)
        {
            productsQuery.Where(p => p.Category == category);
        }

        IList<Product> products = productsQuery
            .OrderBy(p => p.Id)
            .Desc
            .Skip((pageNumber - 1) * pageSize)
            .Take(pageSize)
            .List<Product>();

        return products;
    }

    //...
}
4

3 回答 3

2

inmemory 数据库的代码比 mocking 少得多,更容易理解,更接近真实的东西。它还确保您的映射是正确的,因此不需要额外的负载保存测试。

//for all tests

static Configuration config;
static ISessionFactory testSessionFactory;

config = Fluently.Configure()
    .Database(SQLiteConfiguration.Standard.InMemory().ShowSql().FormatSql())
    .Mappings(m => m.AutoMappings.Add(AutoMap.AssemblyOf<Foo>())  // add your mappings here
    .BuildConfiguration();

testSessionFactory = config.BuildSessionFactory();

// in test
public ProductTests()
{
    session = sf.OpenSession();
    new SchemaExport(config).Execute(true, true, false, session.Connection, null);
}

private void InjectSampleData(params object[] objects)
{
    foreach (var obj in objects)
    {
        session.Save(obj);
    }
    session.Flush();
    session.Clear();
}

public void TestThis()
{
    InjectSampleData(
        new Product() { ... },
        new Product() { ... },
        new Product() { ... },
        new Product() { ... },
    );

    var products = new ProductFacade(session).GetProductsByPageAndCategory(...);

    // assert products match expected subcollection of Injected Data
}
于 2013-10-09T14:32:01.800 回答
2

这是我的替代方案 - 不要模拟数据库。

在我们的测试设置中,每个开发人员的机器上都必须有一个具有给定名称的数据库(例如“CMS_AutoTests”)。当测试运行时,它会与这个数据库交互。

在每次测试之后运行的TearDown方法会运行一个清除每个表的存储过程,因此每次测试都从一个空数据库开始。

于 2013-09-29T20:59:17.320 回答
2

我还使用 moq 来模拟 NHibernate 会话,这是一个非常简单的示例,说明如何模拟 NHibernateISessionISessionFactory.

    var mockSession = new Mock<ISession>();
    mockSession.Setup(r => r.Get<ExampleEntity>(It.IsAny<int>()))
        .Returns(new ExampleEntity());

    var mockSessionFactory = new Mock<ISessionFactory>();
    mockSessionFactory.Setup(r => r.OpenSession())
        .Returns(mockSession.Object);

    var sessionFactory = mockSessionFactory.Object;
    // inject mockSessionFactory.Object to your business layer...

    // code where ever sessionFactory is used...
    // OpenSession now returns the mocked session
    using (var session = sessionFactory.OpenSession())
    {
        //Get of type ExampleEntity will always return whatever you define in your mock
        var rs = session.Get<ExampleEntity>(1);
    }

要为您的业务对象使用模拟,您必须以您可以手动构造它的方式对其进行设计,以便它使用您的模拟工厂。

例如,如果您在 Unity 中使用注入,通常这很容易。通过统一,您的 Business 类的构造函数可能会采用会话或工厂或其他任何东西......在这种情况下,在您的单元测试中,您可以手动构建目标并将您的模拟传递给它......

于 2013-09-29T14:16:12.000 回答