Click here to Skip to main content
15,868,420 members
Articles / Programming Languages / C#

Integration Testing Made Easy Part 1: Repository Testing

Rate me:
Please Sign up or sign in to vote.
4.40/5 (15 votes)
18 Jun 2019CPOL7 min read 108.3K   45   13
Step by step to your first unit testing

Introduction

We are all familiar with a very common scenario while coding in a business application. In fact, this is the most frequent scenario where we want to save an object to the database. But how would we know that our code is functioning properly? Well, there are many ways we could know. Some are good ways to follow and some are not. Let’s discuss using a scenario.

Example Scenario

Suppose we want to save a Student object where the class will have Name, Phone, Email and Id. To save this object, we should create a repository class named StudentRepository. In this class, we will write our data saving codes.

Now there are some points I want to mention. It is good practice to create an interface for each of the repository classes. It is a subset of Repository Pattern.

In our case, we should create IStudentRepository where we will define only Save method and make the StudentRepository class to implement this interface.

So, in summary, we have three projects. Those are DataAccess, DataAccess.Contract, and Domain up to this state. Below are the class definitions and project architecture.

Image 1

Entity Framework

For implementing the database access code, we will not use traditional SqlClient library classes and don't write the traditional SQL queries. Rather, we will use the Entity Framework instead. Entity Framework (EF) is an object-relational mapper that enables .NET developers to work with relational data using domain-specific objects. It eliminates the need for most of the data-access code that developers usually need to write.

To use that framework in our project, we need to install that. But where would we find that library? Well. Microsoft has developed an extension by which we can install, update and uninstall the external libraries to our project in a very easy way. Below is how can we install the Entity Framework into our DataAccess Project..

Walkthrough: Install Entity Framework using Nuget

Image 2

Image 3

Image 4

Image 5

Image 6

  1. Right click on the reference option of the DataAccess project.
  2. Find the Entity Framework item (second in the below picture).
  3. Click the “install” button of that item.
  4. Click Accept when you are asked for the license agreement.
  5. After successful installation, you should see the green sign instead of the “install” button.

After installing the entity framework, we should create a class DataContext which will inherit DBContext class and we will map our class Student with the table name under OnModelCreating method. When the DataContext class is called for the first time, the Entity Framework will look for the Database and create the database by itself if that does not exist. Next, it will create the tables according to the instruction we gave in OnModelCreating method. From the below class, the system will create a database named MockingPractices.DataAccess.DataContext in .\SQLEXPRESS server (since we didn't give any connection string, it will do it in the default server). And also, the Student table is created.

The Database

Image 7

The DataContext Class
C#
namespace MockingPractices.DataAccess
{
    using System.Data.Entity;
    using MockingPractices.Domain;

    public class DataContext:DbContext 
    {
        public DbSet<Student> Students { get; set; }
        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            modelBuilder.Entity<Student>().ToTable("Student");
            base.OnModelCreating(modelBuilder);
        }
    }
}
The IStudentRepository Interface
C#
namespace MockingPractices.DataAccess.Contract
{
    using MockingPractices.Domain;

    public interface IStudentRepository
    {
        int Save(Student student);
    }
}
The StudentRepository Class
C#
namespace MockingPractices.DataAccess
{
    using MockingPractices.DataAccess.Contract;
    using MockingPractices.Domain;

    public class StudentRepository : IStudentRepository
    {
        public int Save(Student student)
        {
            using (var context=new DataContext())
            {
                Student studentAdded = context.Students.Add(student);
                context.SaveChanges();
                return studentAdded.Id;
            }
        }
    }
}

Unit Testing

Now we will find a way to test our codes. In a tradition way, we would have to create a Simple User Interface (might be Windows Forms Application) where there will be a button. If we click the button, we will create a student object and pass it to the repository method. Below is the scenario.

Class Diagram

Image 8

User Interface Based Testing Architecture

Image 9

But if we frequently change our code and need to test, then every time we must run the UI and hit the button for test. Things got worse if we need to test multiple scenarios for a single repository save method. So, what we can understand is that we need a system which can automatically manage the calling of those methods. We don’t need to click and click the user interface for each change of the development code. Below may be one of the proposed architectures.

Automated Testing Architecture

Image 10

This type of testing is named as automated unit testing and currently, there are a couple of frameworks for this purpose. NUnit and Visual Studio’s internal Unit testing framework both are very common. Let’s use the second one in our solution. Below is how you can create a Unit Test project to your solution. If you still don't get the idea, don't worry. Just keep reading below. Smile | <img src= " />

Go to: Add New Project-->Visual C# --> Test --> Unit Test Project

Give an appropriate name and then press OK button.

Image 12

Each of the unit testing frameworks has some classes by which the compiler understands to which classes it should run. This tag is TestClass for this and the required test methods must have TestMethod tag on top of it.

In our case, we can rename the default class to StudentRepositoryTest class and rename the given template method to SaveShouldReturnSavedId method.

So, the test method now looks like below:

Image 13

Philosophy of the Unit Testing

Let’s begin with a very sad but true scenario. Suppose one day you are in a romantic mode, want to talk with your lover and you say “I Love You Jaan”. What do you expect to hear? We all expect “I love you too honey” or similar types of line in reply. But if your lover shouts at you then that shouting will definitely not be matched with your expectation. Am I right?

Image 14

In the programming world, we expect our method to work smoothly without any problem. We know exactly what to expect from a specific method. In our scenario, we expect our repository method to save the student object and returns us the saved id of that object. And we also know that Id must not be zero because our database’s primary key is an auto incremented number and there is no way for the object to be saved in the id 0 row. So, our expectation is the returned value should be not equal to zero. Right? Makes sense?

So how would we implement that scenario in our code?

There is a class named Assert made by Microsoft. Its duty is to match the expected value to the returned/actual value. If the expectation matches with the actual, it shows green but if the expectation is mismatched, it shows red. So the code will look like below:

C#
namespace MockingPractices.DataAccess.Test
{
    using System.Transactions;
    using Microsoft.VisualStudio.TestTools.UnitTesting;
    using MockingPractices.DataAccess.Contract;
    using MockingPractices.Domain;
    [TestClass]
    public class StudentRepositoryTest
    {
        [TestMethod]
        public void SaveShouldReturnSavedId()
        {
            using (TransactionScope scope = new TransactionScope())
            {
                IStudentRepository studentRepository = new StudentRepository();
                Student student = new Student()
                {
                    Id = 0,
                    Name = "test name",
                    Email = "testemail@email.com",
                    Phone = "123456"
                };
                int id = studentRepository.Save(student);
                Assert.AreNotEqual(0, id);
            }
        }
    }
}

Now if we follow the below images, we can instruct the system to run the test method and execute the code inside that method.

Walkthrough: Run the Test Method Using Visual Studio Unit Testing Framework

Image 15

Image 16

Image 17

Image 18

  1. Move your cursor to the icon given in the below image.
  2. Click on that and press Run.
  3. A window will appear which indicates the status of the running test.
  4. If the test runs successfully, the following image should appear.

If you strictly follow my above instructions, you should now see the green sign as given below. Thus, we can test our database code using unit testing without the help of any kinds of User Interface.

But there are some problems in the above work.

  1. We should not retain our test data into the database and
  2. We should not create the helping objects by us. Below is the way in which we can solve those problems.

The main rule is that we must revert the database insert operation after the test method. We can use TransactionScope class for that.

Secondly, we should use a framework to create those helping stubs. We will use NBuilder to build the objects for us. Installation of NBuilder can be done using Nuget.

You should see the installed packages in your project by going to the below image:

Image 19

So, after coding to solve these problems, our code should look like this:

C#
namespace MockingPractices.DataAccess.Test
{
    using System.Transactions;
    using FizzWare.NBuilder;
    using Microsoft.VisualStudio.TestTools.UnitTesting;
    using MockingPractices.DataAccess.Contract;
    using MockingPractices.Domain;

    [TestClass]
    public class StudentRepositoryTest
    {
        [TestMethod]
        public void SaveShouldReturnSavedId()
        {
            using (TransactionScope scope = new TransactionScope())
            {
                IStudentRepository studentRepository = new StudentRepository();
                Student student = Builder<Student>.CreateNew().With(s => s.Id = 0).Build();
                int id = studentRepository.Save(student);
                Assert.AreNotEqual(0, id);
            }
        }
    }
}

Run as many as you like the test just pressing the Run command. You will never need to open the user interface again and again and input the values and calculate the expected values by yourself. This is the true beauty of unit testing.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer Secure Link Services Ltd.
Bangladesh Bangladesh
I am Software Engineer currently working in Secure Link Services Ltd. (http://selise.ch) and I also take classes on various topics of .NET Technologies at BASIS .NET Training Program (http://www.basis.org.bd/index.php/training), which is the best training program in Bangladesh.

Comments and Discussions

 
QuestionDuring unit test data should not save Pin
Tridip Bhattacharjee21-Mar-16 2:55
professionalTridip Bhattacharjee21-Mar-16 2:55 
SuggestionNot a unit test Pin
Aaditya Hasiyan8-Jan-16 2:34
Aaditya Hasiyan8-Jan-16 2:34 
GeneralMy vote of 1 Pin
Daniel Baharestani29-Jan-15 11:46
Daniel Baharestani29-Jan-15 11:46 
GeneralMy vote of 3 Pin
mr_squall16-Dec-14 22:55
mr_squall16-Dec-14 22:55 
GeneralMy vote of 5 Pin
Unque12-Nov-12 14:49
Unque12-Nov-12 14:49 
QuestionConnection String Pin
Fabio Galante Mans8-Nov-12 2:26
Fabio Galante Mans8-Nov-12 2:26 
AnswerRe: Connection String Pin
Foyzul Karim8-Nov-12 4:19
professionalFoyzul Karim8-Nov-12 4:19 
GeneralRe: Connection String Pin
Fabio Galante Mans8-Nov-12 5:32
Fabio Galante Mans8-Nov-12 5:32 
GeneralRe: Connection String Pin
Foyzul Karim8-Nov-12 6:03
professionalFoyzul Karim8-Nov-12 6:03 
GeneralMy vote of 2 Pin
John Brett8-Nov-12 0:46
John Brett8-Nov-12 0:46 
GeneralRe: My vote of 2 Pin
Foyzul Karim8-Nov-12 1:25
professionalFoyzul Karim8-Nov-12 1:25 
GeneralRe: My vote of 2 Pin
John Brett8-Nov-12 1:35
John Brett8-Nov-12 1:35 
GeneralRe: My vote of 2 Pin
Foyzul Karim12-Nov-12 17:42
professionalFoyzul Karim12-Nov-12 17:42 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.