Click here to Skip to main content
12,507,058 members (58,947 online)
Click here to Skip to main content
Add your own
alternative version

Stats

106.8K views
4K downloads
89 bookmarked
Posted

MVC Unit Testing Unleashed

, 14 May 2014 CPOL
Rate this:
Please Sign up or sign in to vote.
In this article we will learn how to perform Unit Testing in Asp.Net MVC

Prerequisites

We are going to talk about MVC unit testing, so it’s must to have at least basic idea about MVC.

You should know,

  • What is the purpose of MVC?
  • How MVC Works?
  • What are different ways of passing data between different layers of MVC application?
  • How to perform navigation in MVC?

If you are new to Asp.net MVC, please try to find answers for above questions first. Click here for our learn MVC step by step series.

What we will learn?

Note

As you can see, I have broken down this article into many sub topics. Article is written considering every reader is completely new to Unit Testing. If you know any of the sub topic listed above, you can skip that and move to next sub topic J.

Basics of Unit Testing

When we hear the word Asp.Net MVC mainly two things comes to our mind.

  • Full control over HTML
  • Easy to Unit Test.

If you are already familiar with basics of unit testing then directly start with “Way towards MVC Unit Testing”.

What is Unit Testing?

Very basic definition will be, testing of every smallest testable block of a code in an automated manner.

Still confused?

Let me make it simpler.

  • In real world every application comprises of many modules. For instance consider a simple E-Commerce application may comprises of Inventory Module, Customer management Module, Order module etc.
  • Every Module is made of using more than one classes.
  • Every class exposes many functionalities in the form of functions.

In Unit Testing we test these functions individually in an automated manner.

What exactly mean by “Automated Manner”?

We will write one more code which will do the testing of our other code (testing of the result of a function).

What is the importance of Unit Testing?

To understand this, answer following question without using any tool or application. “What is the result of 996*965/5?”

3 more questions

  • Do you think your answer is correct?
  • If yes, how much time you took to get the result?
  • Can you reuse the calculation process (which was performed in your mind), if the figure in the operation get changed?

    Now just replace the manual work performed inside your mind with a calculator.

  • Now you will be 100% sure about the result.
  • Answer will be quick.
  • Reuse the same calculator for another calculation.

    Automation makes things more accurate, faster and reusable.

When we write automatic unit test cases for our code, it will become a proof which proves that our code is working. The best part is whenever we make any changes in the code, we just rerun the previously written unit test case and confirms that previous things are not broken.

Basic example of Unit Testing

Step 1. Create a class library which need to be tested with following code block.

public class CustomMaths
{
    public int Add(int num1,int num2)
    {
        return Number1 + Number2;
    } 
}

Step 2. Create Unit Testing Project as Follows

Step 3. Add reference of previous class library to this newly created project

Step 4. Create Test class as follows

[TestClass]
public class TestMathsClass
{
    [TestMethod]
    public void TestAdd()
    {
        //Arrange
        CustomMaths maths = new CustomMaths();

        //Act
        int result = maths.Add(6, 5);

        //Assert
        Assert.AreEqual<int>(11, result);
    }
}

Explanation – As you can see Unit Testing follows simple three steps.

  • Arrange - Create objects and prepare everything needed to test functionality
  • Act – Execute and get the output
  • Assert – Compare final output with expected Output

Step 5. Build your solution and open test explorer window from Test > Windows > Test Explorer

Step 6. Right click Test cases and say Run Selected Tests.

Note: In the example we are using hard coded values (5 and 6) for testing but in real life scenario we will not use hard coded values rather will use some kind of data source like excel or database for input parameters and return value.

Way towards MVC Unit Testing

Now you know what is unit testing and how it works. Then it’s time to understand how unit test works in MVC.

What are different types of logic we write?

Normally when we say “Logic” only thing which we think about is “Business Logic”. In real world applications we end up with writing many different types of logics.

Business Logic

Logic related to business. Example Tax calculation, order processing, conversion (from excel to pdf) etc.

Data Transformation Logic

We have Date of Birth stored in our database and we want to display age in the page. Logic which converts our business data to a data specific to view is called Data Transformation logic.

Presentation Logic

Logic which will change the presentation in the page (or any output which end user going to get) based on some value in database (or any other value), is called Presentation Logic. Example – If employee salary is greater than 50k show him in blue color or else show him in green color.

User Interaction logic

Logic will handle different user interactions like clicking of some control is called as User Interaction Logic.

Database Logic

Logic which will handle the database specific code is called Database logic. Example of such kind of logic is executing a store procedure.

Difficulties in testing traditional Web Forms apps.

The best we can do while working with traditional Web Form application is, break it into 3 (or may be more) Layer. Each layer will perform some specific logic. In this case Business logic and Database logic will be written as two separate layer (called Business layer and database layer respectively). Unit testing of these two layers will be easy because they will be written as simple class libraries (with set of classes and functions) and thus two layers can be tested in the same way we did above.

Here the problem is,

  • UI is tightly coupled to code behind.
  • User Interaction logic, Presentation Logic and Data Transformation logic will be written inside code behind.
  • Unit testing of code behind is not possible because code behind contains Event handlers and invoking event handler as a function will be very difficult task because it mostly have two parameters called “object sender” and “EventArgs e” which cannot be generated programmatically

Thus Unit Testing of User Interaction Logic, Data Transformation logic and Presentation logic will not be possible.

Testing in MVC?

Basic components of Asp.Net MVC are,

  • Model – Business data and Business logic.
  • View – Aspx or Razor (or may be some user defined) UI contain some visual elements.
  • Controller – Handles the user Interaction logic.

1. User Interaction Logic testing

As we know,

  • Every request in Asp.Net MVC go via Controller.
• Controller contain the user interaction logic.
• Controller is not tightly coupled with View

Thus testing of User Interaction logic is possible in Asp.Net MVC.

Code Demonstration

Asp.Net MVC User interaction testing or Controller testing consist of

  • Testing for ViewResult
  • Testing of ViewData/ ViewBag
  • Testing For RedirectResult

Demo 1 – Testing for ViewResult

Let’s assume we have following action method.

//Action Method
public ActionResult GetView(int id)
{
    if (id == 0)
    {
        return View("View2");
    }
    else
    {
        return View("View1");
    }
}

Our task is to create a test method which will confirm whether action method generates proper ViewResult or not.

//Test Cases
[TestMethod]
public void TestForViewWithValue0()
{
    //Arrange
    TestingController t = new TestingController();

    //Act
    ViewResult r = t.GetView(0) as ViewResult;
            
    //Asert
    Assert.AreEqual("View2", r.ViewName);
          
}

[TestMethod]
public void TestForViewWithValueOtherThanZero()
{
    //Arrange
    TestingController t = new TestingController();

    //Act
    ViewResult r = t.GetView(1) as ViewResult;
            
    //Asert
    Assert.AreEqual("View1", r.ViewName);
          
}

Demo 2 – Testing for ViewData/ ViewBag

Let’s assume we have following action method.

//Action Method
public ActionResult Action2()
{
    ViewData["Name"] = "SomeName";
    return View();
}

Our task is to create a test method which will confirm whether action method generates proper ViewData or not.

//Test Cases
[TestMethod]
public void TestForViewData()
{
    //Arrange
    TestingController t = new TestingController();

    //Act
    ViewResult r = t.Action2() as ViewResult;


    //Asert
    Assert.AreEqual("Sukesh", r.ViewData["Name"]);

}

Demo 3 – Testing for Redirection

Let’s assume we have following action method.

//Action Method
public ActionResult Details(int Id)
{
    if (Id < 0)
        return RedirectToAction("Index","SomeElse");

    return View("Details");

}

Our task is to create a test method which will confirm whether action method is redirecting to proper location or not.

//Test Cases
[TestMethod]
public void TestDetailsForRedirect()
{
    TestingController controller = new TestingController();
    var result = controller.Details(-1) as RedirectToRouteResult;
    Assert.AreEqual("Index", result.RouteValues["action"]);
    Assert.AreEqual("SomeElse", result.RouteValues["controller"]);
}
[TestMethod]
public void TestDetailsForViewResult()
{
    TestingController controller = new TestingController();
    ViewResult result1 = (ViewResult)controller.Details(2);
    Assert.AreEqual("Details", result1.ViewName);
}

Note: Testing steps won’t get change here. Once the test cases are created simply build it and from test explorer windows execute the test cases as shown in “Basic example of Unit Testing”.

2. Business Logic

As we said before Business logic and Business data is a part of Model in Asp.Net MVC.
Business logic will be implemented as a simple .Net class with couple of functions. We can easily unit test it in the same way we did in “Basic example of Unit Testing”.

3. Database Logic

In Asp.Net MVC talk nowhere clearly spoken about the database layer. We
usually make it as a separate layer which will be accessed via Business Layer.
Again at the end of the day it’s going to be a single class with couple of function.
Unit testing will be same like above.

4. Data transformation Logic and Presentation Logic.

This is where all voice go down. These two logic decides what data need to
be displayed and how.
They are directly associated with the view. If we write such logic in View unit testing
will not be possible.

Let’s look at an application which contain Data Transformation logic and Presentation logic in the view itself.

What we have?
  • Employee Model
public class Employee
{
    public string EmployeeName { get; set; }
    public string Address { get; set; }
    public DateTime DateOfBirth { get; set; }
    public int Salary { get; set; }
}
  • Employee Controller
public class EmployeeController : Controller
{
    public ActionResult Show()
    {
        Employee e = GetEmployee();
        return View(e);
    }&hellip;
}
  • Employee Show View (Show.cshtml)
<div>
    Employee Detail<br />
    Employee Name : @Model.EmployeeName<br />
    Address : @Model.Address


    <br />
    @{
        int age = DateTime.Now.Year - Model.DateOfBirth.Year;
        if (Model.DateOfBirth > DateTime.Now.AddYears(-age))
        {
            age--;
        }
    }
    Age : @age


    <br />
    @if (Model.Salary > 20000)
    {
        <span style="color: red">Salary : @Model.Salary</span>

As you can see, we are

  • Converting date of birth to age and then displaying it - data transformation logic.
  • Based on the salary color of the display text is changing – presentation logic.

Such kind of tightly coupling between UI Design, Presentation logic and Data transformation logic becomes an obstacle for complete unit testing.

What’s the solution?

Solution will be logical more than technical.

We will introduce one more layer between Model and View and call it ViewModel.

Model will be identified as data and logic related to business whereas ViewModel will be identified as data and logic related to View.

There will not be any direct connection between Model and the view. View will always connect to ViewModel which will contain

  1. Reference to the Model
  2. Data Transformation logic as per requirement in the View.
  3. Presentation logic based on the View requirement.

So, the first step will be creating Employee View Model as follows.

public class EmployeeVM
{
    public Employee emp { get; set; }
   
    public EmployeeVM(Employee e1)
    {
        emp = e1;
    }
    public int Age
    {
        get
        {
            int age = DateTime.Now.Year - emp.DateOfBirth.Year;
            if (emp.DateOfBirth > DateTime.Now.AddYears(-age))
            {
                age--;
            }
            return age;
        }
    }


    public string SalaryColor
    {
        get
        {
            if(emp.Salary>20000)
            {
                return "red";
            }
            else
            {
                return "green";
            }
        }
    }
}

Second step will be making view a strongly typed view of ViewModel class instead of Model as follows.

<div>
    Employee Detail<br />
    Employee Name : @Model.emp.EmployeeName<br />
    Address : @Model.emp.Address <br />
    Age : @Model.Age
        <br />
    <span style="color:@Model.SalaryColor">Salary : @Model.emp.Salary</span>
</div>
Here we are. View Model is simply a class with two properties which can be
tested using simple unit testing logic. That means our presentation logic and data
transformation logic is now testable.

See the following video on View Model in ASP.NET MVC: -

Conclusion

MVC is an architectural pattern meant for solving UI level problems. We had just saw how we separate our UI from logic completely and makes our each and every logical code a testable code.Keep coding, Keep learning and Keep sharing.

Don’t forget to vote and comment.

For technical trainings on various topics like WCF, MVC, Business Intelligence, Design Patterns, WPF,

TFS and Basic fundamentals feel free to contact SukeshMarla@Gmail.com or visit www.sukesh-marla.com

For more stuff like this click here. Subscribe to article updates or follow at twitter @SukeshMarla

See 600+ above FAQ questions and answers in .NET, C#, ASP.NET, SQL, WCF, WPF, WWF, SharePoint, Design patterns, UML etc.

License

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

Share

About the Author

Marla Sukesh
Instructor / Trainer Train IT
India India
Learning is fun but teaching is awesome.

Code re-usability is my passion ,Teaching and learning is my hobby, Becoming an successful entrepreneur is my goal.

By profession I am a Corporate Trainer.
I do trainings on WCF, MVC, Business Intelligence, Design Patterns, HTML 5, jQuery, JSON and many more Microsoft and non-Micrsoft technologiees.

Find my profile here



My sites



@Twitter
@Facebook

You may also be interested in...

Comments and Discussions

 
QuestionHow should we view the test outputs? Pin
Member 1262440014-Jul-16 17:07
memberMember 1262440014-Jul-16 17:07 
Questiongreat Pin
zekikaya12-Apr-16 21:27
memberzekikaya12-Apr-16 21:27 
AnswerRe: great Pin
Marla Sukesh14-Apr-16 20:15
mvp Marla Sukesh14-Apr-16 20:15 
Suggestionbug Pin
Member 939404115-Mar-16 19:41
memberMember 939404115-Mar-16 19:41 
GeneralRe: bug Pin
Marla Sukesh14-Apr-16 20:34
mvp Marla Sukesh14-Apr-16 20:34 
Questionthanks very very Pin
Member 1159918827-Oct-15 3:21
memberMember 1159918827-Oct-15 3:21 
AnswerRe: thanks very very Pin
Marla Sukesh14-Apr-16 20:35
mvp Marla Sukesh14-Apr-16 20:35 
Questionnice article for starters, but... Pin
Ibrahim ben Salah15-Sep-15 11:38
memberIbrahim ben Salah15-Sep-15 11:38 
QuestionThanks Pin
Mohammed Nhari8-Sep-15 6:27
memberMohammed Nhari8-Sep-15 6:27 
AnswerRe: Thanks Pin
Marla Sukesh25-Sep-15 8:27
mvp Marla Sukesh25-Sep-15 8:27 
QuestionSimple, good article, easily understood. However... Pin
youngtexas18-Aug-15 12:30
memberyoungtexas18-Aug-15 12:30 
GeneralThanks :) Pin
Adil A Shaikh15-May-15 23:07
memberAdil A Shaikh15-May-15 23:07 
GeneralMy vote of 4 Pin
JM Pironneau27-Oct-14 0:54
memberJM Pironneau27-Oct-14 0:54 
GeneralMy vote of 5 Pin
Humayun Kabir Mamun8-Oct-14 18:47
memberHumayun Kabir Mamun8-Oct-14 18:47 
GeneralMy vote of 5 Pin
Alexandra Christina16-Jul-14 11:27
memberAlexandra Christina16-Jul-14 11:27 
GeneralRe: My vote of 5 Pin
Marla Sukesh20-Jul-14 4:46
professional Marla Sukesh20-Jul-14 4:46 
GeneralMy vote of 5 Pin
JasonMacD15-May-14 6:26
memberJasonMacD15-May-14 6:26 
GeneralRe: My vote of 5 Pin
Marla Sukesh15-May-14 9:44
professionalMarla Sukesh15-May-14 9:44 
QuestionUnit testing Private method Pin
JustLikeSummer15-May-14 3:20
memberJustLikeSummer15-May-14 3:20 
AnswerRe: Unit testing Private method Pin
axy10815-May-14 10:34
professionalaxy10815-May-14 10:34 
GeneralRe: Unit testing Private method Pin
JustLikeSummer29-May-14 1:33
memberJustLikeSummer29-May-14 1:33 
AnswerRe: Unit testing Private method Pin
Marla Sukesh15-May-14 17:19
professionalMarla Sukesh15-May-14 17:19 
QuestionGreat Notes Pin
koolprasad200315-May-14 2:09
memberkoolprasad200315-May-14 2:09 
AnswerRe: Great Notes Pin
Marla Sukesh15-May-14 4:47
professionalMarla Sukesh15-May-14 4:47 
GeneralMy vote of 5 Pin
Renju Vinod14-May-14 21:27
professionalRenju Vinod14-May-14 21:27 
GeneralRe: My vote of 5 Pin
Marla Sukesh15-May-14 4:46
professionalMarla Sukesh15-May-14 4:46 
GeneralMy vote of 4 Pin
Akiii00111-May-14 20:06
memberAkiii00111-May-14 20:06 
GeneralRe: My vote of 4 Pin
Marla Sukesh13-May-14 17:35
professionalMarla Sukesh13-May-14 17:35 
GeneralRe: My vote of 4 Pin
Marla Sukesh14-May-14 16:55
professionalMarla Sukesh14-May-14 16:55 
Questionvery nice Pin
BillW339-May-14 9:31
professionalBillW339-May-14 9:31 
AnswerRe: very nice Pin
Marla Sukesh9-May-14 20:29
professionalMarla Sukesh9-May-14 20:29 
GeneralMy vote of 5 Pin
Member 108057699-May-14 3:49
memberMember 108057699-May-14 3:49 
GeneralRe: My vote of 5 Pin
Marla Sukesh9-May-14 20:27
professionalMarla Sukesh9-May-14 20:27 
QuestionGood One Pin
Member 108057698-May-14 19:47
memberMember 108057698-May-14 19:47 
AnswerRe: Good One Pin
Marla Sukesh8-May-14 19:49
professionalMarla Sukesh8-May-14 19:49 
Generalgood work Pin
ashok kusampudi k5-May-14 9:30
memberashok kusampudi k5-May-14 9:30 
GeneralRe: good work Pin
Marla Sukesh5-May-14 16:49
professionalMarla Sukesh5-May-14 16:49 
GeneralRe: good work Pin
Member 1023952719-Jan-15 6:44
memberMember 1023952719-Jan-15 6:44 
GeneralGood one Pin
Omar Gameel Salem4-May-14 13:51
memberOmar Gameel Salem4-May-14 13:51 
GeneralRe: Good one Pin
Marla Sukesh4-May-14 17:28
professionalMarla Sukesh4-May-14 17:28 
GeneralExcellent Article Pin
Member 45800921-May-14 2:14
memberMember 45800921-May-14 2:14 
GeneralRe: Excellent Article Pin
Marla Sukesh1-May-14 5:23
professionalMarla Sukesh1-May-14 5:23 
Question. Pin
Member 1037574427-Apr-14 9:14
memberMember 1037574427-Apr-14 9:14 
AnswerRe: . Pin
Marla Sukesh27-Apr-14 16:20
professionalMarla Sukesh27-Apr-14 16:20 
GeneralGreat Article! Pin
arinpcssouth27-Apr-14 8:12
memberarinpcssouth27-Apr-14 8:12 
GeneralRe: Great Article! Pin
Marla Sukesh27-Apr-14 16:20
professionalMarla Sukesh27-Apr-14 16:20 
QuestionGood Explanation.. Pin
Pinna Nageshwar Rao24-Apr-14 23:22
memberPinna Nageshwar Rao24-Apr-14 23:22 
AnswerRe: Good Explanation.. Pin
Marla Sukesh25-Apr-14 1:51
professionalMarla Sukesh25-Apr-14 1:51 
QuestionGood article! Pin
James Jensen24-Apr-14 4:25
professionalJames Jensen24-Apr-14 4:25 
AnswerRe: Good article! Pin
Marla Sukesh24-Apr-14 7:53
professionalMarla Sukesh24-Apr-14 7:53 

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.

| Advertise | Privacy | Terms of Use | Mobile
Web02 | 2.8.160927.1 | Last Updated 14 May 2014
Article Copyright 2014 by Marla Sukesh
Everything else Copyright © CodeProject, 1999-2016
Layout: fixed | fluid