存储库模式的接口有什么特别的用途?

时间:2013-08-04 12:42:20

标签: asp.net-mvc repository-pattern repository-design

我完全理解了Repository模式设计的想法。但是为什么我们需要实现iDepository接口类呢?这有什么特别的用途? 存储库类本身在没有接口类的情况下工作。

我认为有人会回答我这是为了脱离业务逻辑和数据逻辑。 但即使没有接口类,是不是数据逻辑解耦数据逻辑?

3 个答案:

答案 0 :(得分:2)

当您对业务层进行单元测试时,可以注入一个IRepository类的测试对象。这有以下好处:

  1. 它允许您轻松查明由业务层而不是存储库层引起的失败测试;
  2. 它使您的业务逻辑层测试快速,因为它们既不依赖于数据访问,也不依赖于数据访问,也不会设置数据库结构和测试数据,这往往非常慢。
  3. 通过构造函数注入进行单元测试时,注入测试的一种方法是双倍的。假设您的存储库具有以下方法:

    void Add(Noun noun);
    int NumberOfNouns();
    

    这是您商务舱的代码:

    public class BusinessClass {
    
        private IRepository _repository;
    
        public BusinessClass(IRepository repository) {
            _repository = repository;
        }
    
        // optionally, you can make your default constructor create an instance
        // of your default repository
        public BusinessClass() {
            _repository = new Repository();
        }
    
        // method which will be tested 
        public AddNoun(string noun) {
            _repository.Add(new Noun(noun));
        }
    }
    

    要测试AddNoun而不需要真正的存储库,您需要设置测试双精度。通常你会通过使用像Moq这样的模拟框架来做到这一点,但我会从头开始编写一个模拟类来说明这个概念。

    public IRepository MockRepository : IRepository {
        private List<Noun> nouns = new List<Noun>();
    
        public void Add(Noun noun) {
            nouns.Add(noun);
        }
    
        public int NumberOfNouns() {
            return nouns.Count();
        }
    }
    

    现在你的一个测试就是这个。

    [Test]
    public void AddingNounShouldIncreaseNounCountByOne() {
        // Arrange
        var mockRepository = new MockRepository();
        var businessClassToTest = new BusinessClass(mockRepository);
    
        // Act
        businessClassToTest.Add("cat");
    
        // Assert
        Assert.AreEqual(1, mockRepository.NumberOfNouns(), "Number of nouns in repository should have increased after calling AddNoun");
    
    }
    

    这实现了您现在已经测试了BusinessClass.AddNoun方法的功能,而无需触及数据库。这意味着即使您的Repository层存在问题(例如连接字符串出现问题),您也可以确保您的Business层按预期工作。这包括上面的第1点。

    对于上面的第2点,无论何时编写测试数据库的测试,都应确保在每次测试之前它处于已知状态。这通常涉及在每次测试开始时删除所有数据并重新添加测试数据。如果没有这样做,那么你就不能对表中的行数运行断言,因为你不确定它应该是什么。

    删除和重新添加测试数据通常是通过运行SQL脚本来完成的,这些脚本很慢并且在数据库结构发生变化时容易受到破坏。因此,建议仅将数据库的使用限制在存储库本身的测试中,并在单元测试应用程序的其他方面时使用模拟的存储库。

    至于抽象类的使用 - 是的,这将提供提供测试双精度的相同能力。我不确定你会选择将哪些代码放在抽象基础中,哪些代码具体实现。 This answer to an SO question对抽象类与相互作用进行了有趣的讨论。

答案 1 :(得分:1)

首先,您必须了解存储库模式是什么。它是一个抽象层,因此应用程序的其余部分不必关心数据来自何处。

.NET中的抽象通常由接口表示,因为没有逻辑(代码)可以附加到接口。

作为奖励,界面还可以让您更轻松地测试您的应用程序,因为您可以轻松mock界面(或创建stub

该界面还允许您改进数据层。例如,您可以从为所有存储库类使用数据库开始。但是后来你想要在Web服务背后移动一些逻辑。然后,您只需要使用WCF存储库替换数据库存储库。您可能还发现存储库很慢并且想要在其中实现简单的内存缓存(通过使用memcache或其他东西)

答案 2 :(得分:0)

我找到了一个非常有用的msdn页面,展示了存储库和测试驱动开发的想法 。 http://blogs.msdn.com/b/adonet/archive/2009/12/17/walkthrough-test-driven-development-with-the-entity-framework-4-0.aspx