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?
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:
One way to inject the test doubles when unit testing is by Constructor Injection. Suppose your Repository has the following methods:
And this is the code of your business class:
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.
Now one of your tests could be this.
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.