NHibernate测试,模拟ISession

6

我正在使用NHibernate和Rhinomocks,在测试时遇到了一些问题。我想要测试以下仓库方法,但不想访问数据库(其中_session作为ISession注入到仓库中):

public class Repository : IRepository
{
    (... code snipped for brevity ...)

    public T FindBy<T>(Expression<Func<T, bool>> where)
    {  
        return _session.Linq<T>().Where(where).FirstOrDefault();
    }
}

我的初始方法是模拟ISession,并在调用Linq时返回一个IQueryable存根(手工编码)。 我有一个客户对象的IList,我想在内存中查询它以测试我的Linq查询代码,而不必访问数据库。 但我不确定这会是什么样子。 我需要编写自己的IQueryable实现吗? 如果是这样,有人为这种方法做过吗? 还是我需要看其他途径?

谢谢!

2个回答

7

我是这样做测试的,不将表达式传递给存储库,而是公开IQueryable,为存储库提供接口,例如:

public interface IRepository<T>
{
    IQueryable<T> All();
    // whatever else you want
}

很容易就可以实现:

public IQueryable<T> All()
{
    return session.Linq<T>();
}

这意味着您不再需要在存储库上调用方法,而是:
var result = repository.FindBy(x => x.Id == 1);

您可以做以下事情:

var result = repository.All().Where(x => x.Id == 1);

或者使用 LINQ 语法:

var result = from instance in repository.All()
             where instance.Id == 1
             select instance;

这意味着您可以直接模拟存储库来获得相同的测试,这应该更容易。您只需让模拟返回您创建并调用AsQueryable()的列表即可。
正如您所指出的那样,这样做的目的是让您在不涉及数据库的情况下测试查询逻辑,否则会大大降低速度。

如果您的受测代码也调用了result.FirstOrDefault(),那么您该如何对该代码进行模拟? - David Gardiner
如果您创建一个列表并在其上调用AsQueryable(),那么.FirstOrDefault()将直接针对原始列表的内容进行操作。您不必模拟任何针对可查询对象的调用,因为它是一个真正的IQueryable对象。 - Garry Shutler
我们最终采用了这种方法 - 它非常有效,尽管这意味着大多数存储库只有单个属性(在您的示例中为 All(),在我们的情况下为 Queryable)。 - zcrar70

0

从我的角度来看,这应该被视为集成测试。NHibernate有自己的测试,它通过了这些测试,而你似乎正在尝试在自己的测试套件中复制其中一些测试。我要么将NHibernate代码和测试添加到您的项目中,并将其与其测试一起添加到那里,如果他们没有非常相似的测试,则使用他们的测试方法,要么将其移动到集成测试场景并连接数据库。

如果您只是不想设置数据库进行测试,那么您很幸运,因为您正在使用NHibernate。通过一些搜索,您可以找到相当多的示例,说明如何使用SQLite“有点”与数据库进行集成测试,但将其保留在内存中。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接