仓储模式和内存单元测试

21

我看过一些实现了仓储模式的代码,非常简单易懂,这些代码都在stackoverflow的其他答案中提到过。

http://www.codeproject.com/Tips/309753/Repository-Pattern-with-Entity-Framework-4-1-and-C http://www.remondo.net/repository-pattern-example-csharp/

public interface IRepository<T>
{
    void Insert(T entity);
    void Delete(T entity);
    IQueryable<T> SearchFor(Expression<Func<T, bool>> predicate);
    IQueryable<T> GetAll();
    T GetById(int id);
}

public class Repository<T> : IRepository<T> where T : class, IEntity
{
    protected Table<T> DataTable;

    public Repository(DataContext dataContext)
    {
        DataTable = dataContext.GetTable<T>();
    }
...

如何在单元测试中使其从内存中工作?有没有办法通过内存中的任何内容构建DataContext或Linq表?我的想法是创建一个集合(List,Dictionary...),并在进行单元测试时进行桩操作。谢谢!编辑:我需要像这样的东西:
  • I have a class Book
  • I have a class Library
  • In the Library constructor, I initialize the repository:

    var bookRepository = new Repository<Book>(dataContext)

  • And the Library methods use the repository, like this

    public Book GetByID(int bookID)
    { 
        return bookRepository.GetByID(bookID)
    }
    

在测试时,我希望提供一个内存上下文。在生产环境中,我将提供真实的数据库上下文。


根据您的要求,我添加了一些示例代码。 - Mechanical Object
1个回答

32

我建议使用像MoqRhinoMocks这样的模拟库。这里有一个使用Moq的不错教程here

在决定使用哪个之前,以下内容可能会有所帮助:

额外信息:可以在 这里 找到单元测试框架的比较。


更新:根据发帖者的要求

创建一个内存数据库

var bookInMemoryDatabase = new List<Book>
{
    new Book() {Id = 1, Name = "Book1"},
    new Book() {Id = 2, Name = "Book2"},
    new Book() {Id = 3, Name = "Book3"}
};

模拟您的存储库(以下示例中我使用了 Moq)

var repository = new Mock<IRepository<Book>>();

设置你的代码仓库

// When I call GetById method defined in my IRepository contract, the moq will try to find
// matching element in my memory database and return it.

repository.Setup(x => x.GetById(It.IsAny<int>()))
          .Returns((int i) => bookInMemoryDatabase.Single(bo => bo.Id == i));

通过将您的模拟对象传递给构造函数参数来创建库对象。
var library = new Library(repository.Object);

最后,一些测试:

// First scenario look up for some book that really exists 
var bookThatExists = library.GetByID(3);
Assert.IsNotNull(bookThatExists);
Assert.AreEqual(bookThatExists.Id, 3);
Assert.AreEqual(bookThatExists.Name, "Book3");

// Second scenario look for some book that does not exist 
//(I don't have any book in my memory database with Id = 5 

Assert.That(() => library.GetByID(5),
                   Throws.Exception
                         .TypeOf<InvalidOperationException>());

// Add more test case depending on your business context
.....

3
非常感谢这个教程!但我需要测试一个已经使用仓库的类。创建一个“假”的仓库并通过这种方式进行测试,只能帮助我测试仓库模式是否被正确实现。我将尝试通过编辑来澄清我的问题。 - Kaikus
@Kaikus:如果您能简要地使用存储库实现该类,那将会很有帮助。 - Mechanical Object
所以,如果我理解正确的话,这个想法不是为了存根“上下文”,而是完全模拟存储库。然后,当实例化一个实体时,我总是必须使用构造函数注入它自己的存储库(真实的或模拟的)。谢谢! - Kaikus

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