This article will teach you how to set up a basic service and repository, to isolate your BLL (Business Logic Layer) from your DAL (Data Access Layer), so you can easily create unit tests for your BLL. This solution doesn’t use any ORM (Object Relational Mapping) like e.g. Entity Framework. This is only to explain how to isolate logic from data and how to test your logic in isolation.

Structure

The first thing you need to understand is the structure. We create a service that our application and unit tests use. The service uses some interface for a repository, this could be a real repository that connects to a real database or a mock repository with fake data. This gives us the ability to control what repository our service is using, with Dependency Injection.

Service and Repository structure

The DAL is a simple data transfer layer. It shouldn’t contain any logic. Its only responsibility is to transfer data. All logic happens in our service.

It’s a convention that each repository handles data access for one entity (one database table). If you’re using Entity Framework, you can take a look at my tutorial where I describe how to set up a Generic Repository with Unit Of Work.

Model

To begin with we have to create a model. Let’s begin by creating a very simple model class that represents one student.

Each student has a unique identifier and a name. That’s all we need. Remember, these are basics. We don’t want to make things too complicated.

Interface

If you don’t understand what an interface is, you can think of it as a contract. The user of the interface doesn’t care about implementation details as long as the class implements all methods, fields and properties of the interface.

So let’s create an interface for our repository. It might look something like this:

The interface only has one method that returns all students. This is all we need to begin with.

Repository (DAL)

The DAL is a simple data transfer layer. It shouldn’t contain any logic. Its only responsibility is to transfer data.

So all we have to do now is to to create our repository class that implements our interface and defines the GetAllStudents() function. Simple enough? Let’s do that.

Above you can see that I created a StudentRepository class that implements all of the methods in our IStudentRepository interface, so the class implementation contract is sufficient.

I’m not gonna implement the actual code to get students from the DB because it depends on which SqlProvider you’re using; SQL Server, MySQL, Oracle, etc. However, I recommend using Dapper, it’s an easy way to map results from a database to any object. It’s a Micro-ORM that makes object mapping really easy!

Service (BLL)

The BLL is the layer which contains all logic. You should structure your application so all/most of your logic is in here.

The next step is to create our service that uses our repository. First you need to ask yourself: What should my service be able to do?

Let’s break it down.

  • The class has one private variable of type IStudentRepository, that is our student repository interface.
  • The class has two constructors:
    • The empty constructor will create an instance of our real student repository that connects to the DB.
    • The other constructor takes one parameter that is of type IStudentRepository, so as long as a class implements the IStudentRepository interface, it can be injected into our service.
  • The class has one public method GetAllStudents() that returns a list of all students.

Let’s add one more function to our service class.

The function GetStudentByID(int id) handles getting a student by a unique identifier. First we get all students. We already got a function for that in our repository called GetAllStudents() so we’ll be using that. This returns a list of all the students. Then we use a LINQ query to search for students that match our ID. .Where() returns a collection so we add .SingleOrDefault() in the end. That means that there should be just one student returned with that ID. If there is none, it returns null but if there are more than one, it throws an exception.

Testing

Now we need to test our code with something called a Unit Test. You could also do integration testing, where you would test against a real database with real data. Either way, I prefer the mock way. I will be using Moq mocking framework and UnitTesting framework from Microsoft. Here’s a Quickstart for Moq. I really recommend this mocking framework, it’s great!

Setting up the test

Let’s start off by setting up our test environment. Of course we first need to create a Unit Test project and reference our other project where all of our classes are.

Now we need to create a class and a Test Initializer within that class. The Test Initializer will be run in the beginning of each test.

The test initializer basically creates a new mocked version of our repository so each time we call GetAllStudents() in the repository, this list of pre-defined students will be returned. Of course we won’t be calling the repository method, but our service will. Then we create a new instance of our service class StudentService and inject the mocked repository using Dependency Injection.

Now when creating a test, you can do it the wrong way and you can do it the right way. We want to do it the right way, but first I want to show you how you can do it the wrong way.

The WRONG way

I have seen many people create unit tests where they test their DAL (repository). Like this:

So what’s wrong with this you may ask. The test passes, because there are 3 students in our repository we set up earlier. But think about it for a second, what are you really testing? Absolutely nothing. You’re not testing any logic, which is exactly what you should be testing. You shouldn’t test your DAL (repository). You should be testing your BLL (service) where your logic is, because that is the class your application uses.

The RIGHT way

Now let’s do it the right way with the service we created earlier, where our logic actually is.

Okay, now we’re getting somewhere. Now we’re testing our BLL, which is our business logic layer. But hey, there isn’t any logic? So what’s the difference with this test and the one in the bad example above? Almost none, but bare with me.

Say you change the logic in the GetAllStudents() method in your service and you will get fewer results of students. Then your test will FAIL, indicating that your service is not doing what you’ve expected, which is a clear sign you may want to refactor your application and update your test so it covers all possible outcomes.

I’ll take another better example. Let’s add another function to our StudentService class. Just a simple function that gets a student by his unique ID, goes through his name and adds a space between each letter. Simple enough. The function might look something like this:

Now we have a function in our service that has actual logic. Now we would want to test this logic. Let’s do that by creating a new test function.

Now we’ve successfully tested the logic for one case in AddSpacesToStudentName() function. We wanted to get student’s name nr. 2 with spaces, and that was David so we expected the outcome to be D a v i d and it was. Excellent!

Now how about another case, e.g. when the student doesn’t exist? According to the logic in our service, we throw an exception when the student doesn’t exist. So let’s create another test.

Now we call the same service function AddSpacesToStudentName() but with a student ID that doesn’t exist. We know that it doesn’t exist, because we mocked the repository data earlier in our test initializer. But we have to make sure that the logic is correct and throws an exception. So we add [ExpectedException(typeof(Exception))] on top of the function definition, indicating that we expect an exception of type Exception. And guess what, the test passes! Awesome.

Now I hope you understand the importance of testing your BLL logic in isolation. You shouldn’t be testing your DAL, you really should be testing the logic (BLL) in your application.

I hope this article helps some people understand the basics of setting up a repository for your DAL and a service for your BLL and how to test it. Please leave a comment if you liked it, or if you have any feedback. 🙂