Hoy Cheung
Hoy Cheung

Reputation: 1670

What particular use is the interface for repository pattern?

I fully understand the idea of the design of Repository pattern. But why do we need to implement the iDepository interface class? What particular use is this for? The repository class itself works without the interface class.

I think someone is going to answer me it's for decoupling from the business logic and the data logic. But even if there is no interface class, isn't the data logic decoupled data logic?

Upvotes: 3

Views: 3169

Answers (3)

Hoy Cheung
Hoy Cheung

Reputation: 1670

I found a very useful msdn page demonstrating the idea of Repository and Test Driven Development . http://blogs.msdn.com/b/adonet/archive/2009/12/17/walkthrough-test-driven-development-with-the-entity-framework-4-0.aspx

Upvotes: 0

Polly Shaw
Polly Shaw

Reputation: 3222

It is so that you can inject a test double of the IRepository class when you are unit testing the business layer. This has the following benefits:

  1. It allows you to easily pinpoint failing tests as being caused by the business layer rather than the repository layer;
  2. It makes your business logic layer tests fast, as they depend neither on data access, which tends to be slow, nor set-up of a database structure and test data, which tends to be very slow.

One way to inject the test doubles when unit testing is by Constructor Injection. Suppose your Repository has the following methods:

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

And this is the code of your business class:

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));
    }
}

To test AddNoun without needing a real Repository, you need to set up a test double. Usually you would do this by using a mocking framework such as Moq, but I'll write a mock class from scratch just to illustrate the concept.

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();
    }
}

Now one of your tests could be this.

[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");

}

What this has achieved is that you have now tested the functionality of your BusinessClass.AddNoun method without needing to touch the database. This means that even if there's a problem with your Repository layer (a problem with a connection string, say) you have assurance that your Business layer is working as expected. This covers point 1 above.

As for point 2 above, whenever you're writing tests which test the database you should make sure it's in a known state before each test. This usually involves deleting all the data at the beginning of every test and re-adding test data. If this isn't done then you can't run assertions against, say, the number of rows in a table, because you won't be sure what that's supposed to be.

Deleting and re-adding test data would normally be done by running SQL scripts, which are slow and vulnerable to breakage whenever the database structure changes. Therefore it's advisable to restrict the use of the database only to the tests of the repository itself, and use mocked out repositories when unit testing other aspects of the application.

As for the use of abstract classes - yes, this would provide the same ability to supply test doubles. I'm not sure which code you would choose to put in the abstract base and which the concrete implementation, though. This answer to an SO question has an interesting discussion on abstract classes vs interaces.

Upvotes: 2

jgauffin
jgauffin

Reputation: 101130

First, you must understand what the Repository pattern is. It's an abstraction layer so that rest of the application do not have to care where the data comes from.

Abstractions in .NET is typically represented by interfaces as no logic (code) can be attached to an interface.

As a bonus that interface also makes it easier for you to test your application since you can mock the interface easily (or create a stub)

The interface also allows you to evolve your data layer. You might for instance start by using a database for all repository classes. But later you want to move some logic behind a web service. Then you only have to replace the DB repository with a WCF repository. You might also discover that an repository is slow and want to implement a simply memory cache within it (by using memcache or something else)

Upvotes: 1

Related Questions