2013-08-04 27 views
3

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

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

回答

2

这样,您可以在单元测试业务层时注入IRepository类的测试双精度。这具有以下好处:

  1. 它允许您轻松查明由业务层而不是存储库层引起的失败测试;
  2. 它使您的业务逻辑层测试变得快速,因为它们既不依赖于数据访问(这往往很慢),也不会建立数据库结构和测试数据,而这往往非常缓慢。

单元测试是通过构造函数注入来注入测试的一种方法。假设仓库中有以下方法:

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方法的功能,而无需触摸数据库。这意味着即使您的存储库层存在问题(例如连接字符串存在问题),您可以确保您的业务层按预期工作。这包括上面的第1点。

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

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

至于抽象类的使用 - 是的,这将提供相同的能力来提供测试双打。我不确定你会选择将哪些代码放在抽象基础中,哪些是具体的实现。 This answer to an SO question关于抽象类vs交互有一个有趣的讨论。

+0

如何实现1和2?我还是不明白。你可以平行比较使用接口和抽象类吗?实际上,接口不允许执行方法,我觉得这是浪费代码。 –

+0

我已经扩展了单元测试业务层使用测试双打。 –

1

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

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

作为奖励,该接口也使得它更容易为你测试你的应用程序,因为你可以很容易mock接口(或创建一个stub

该接口还可以让你发展你的数据层。例如,您可能首先使用所有存储库类的数据库。但后来你想要在Web服务背后移动一些逻辑。然后你只需要用WCF仓库替换数据库仓库。您可能还会发现存储库很慢,想要在其中实现一个简单的内存缓存(通过使用memcache或其他内容)

+0

如何使用抽象类? 我正在为包含不同语言(例如英语,法语,意大利语,日语)的字典创建存储库类... 虽然每种语言都有很不同的属性,但它们确实共享一些常用属性,例如名词,动词,等等。对于一些函数,像GetEntry一样,但GetPartofSpeech会有很大的不同。为了减少代码,我应该使用接口还是抽象类? –

+0

实体本身可以包含任何你喜欢的东西。存储库的目的是为这些实体构建和填充信息。因此从存储库的角度来看,实体是否继承基类并不重要。这是应该实现接口的存储库本身。 – jgauffin