Testing an ASP.NET MVC Controller using NUnit

Posted by: Mahesh Sabnis , on 4/1/2015, in Category ASP.NET MVC
Views: 80127
Abstract: Using NUnit to test action methods inside an ASP.NET MVC Controller.

In a previous article, we discussed how to do ASP.NET MVC Model Testing using NUnit and MOQ. Today we will learn how to test another major component of MVC, and that is the Controller. The Controller is responsible for updating model state and also returning a result e.g. views, json, http status code, etc.

Testing the MVC controller means we need to test the action methods which have the following return types:

  • Default View - The View having same name as the name of the action method
  • Specific View - The action method returns a specific view based on the logic.
  • Redirect to URL - Returns the URL of another action method in the same or another controller.
  • Conditional View based on the Model State - The Action method has some logic which changes the model state and based on the model state, a specific view is returned.

 

As a good coding practice for Controllers, we should not write complex code or business logic in action methods. But since the controller action method is applied with Action Filters for Authorization, Exception or other custom action filtration, it does tend to become complex. In this case, the controller should be tested to make sure that it is behaving appropriately based on the model object passed to it.

Creating an ASP.NET MVC Application

Step 1: Open Visual Studio Community Edition and create a MVC application of the name ‘MVC5_Testing_1’. In SQLServer create a database of the name Company. In this database add the following tables.

CREATE TABLE [dbo].[Department] (
    [DeptNo]   INT          NOT NULL,
    [Dname]    VARCHAR (50) NOT NULL,
    [Location] VARCHAR (50) NOT NULL,
    PRIMARY KEY CLUSTERED ([DeptNo] ASC)
);

CREATE TABLE [dbo].[Employee] (
    [EmpNo]   INT          NOT NULL,
    [EmpName] VARCHAR (50) NOT NULL,
    [Salary]  INT          NOT NULL,
    [DeptNo]  INT          NOT NULL,
    PRIMARY KEY CLUSTERED ([EmpNo] ASC),
    FOREIGN KEY ([DeptNo]) REFERENCES [dbo].[Department] ([DeptNo])
);

CREATE TABLE [dbo].[EmployeeInfo] (
    [EmpNo]       INT          IDENTITY (1, 1) NOT NULL,
    [EmpName]     VARCHAR (50) NOT NULL,
    [Salary]      DECIMAL (18) NOT NULL,
    [DeptName]    VARCHAR (50) NOT NULL,
    [Designation] VARCHAR (50) NOT NULL,
    PRIMARY KEY CLUSTERED ([EmpNo] ASC)
);

Step 2: We will add EntityFramework in our application for Data Access. To do so, in the Models folder add a new ADO.NET Entity Data Model, name it as CompanyEDMX. In the wizard, select Generate from Database, select Company database and finally select all tables. After the completion of the wizard, the table mapping will be generated as shown in the following figure.entity-models

Step 3: Since we need to ignore direct calls from the MVC Controllers to the EntityFramework, we will add a new folder in the project with the class containing the logic for accessing the EntityFramework. Add the folder with the name ModelAccess in the project and add a class file in it with the following logic.

using System.Collections.Generic;
using System.Linq;

using MVC5_Testing_1.Models;

namespace MVC5_Testing_1.ModelAccess
{
    /// <summary>
    /// Interface for providing functnality for Department Data Access
    /// </summary>
    public interface IDepartmentAccess
    {
       List<Department> GetDepartments();
       Department GetDepartment(int id);
       void CreateDepartment(Department dept);
       bool CheckDeptExist(int id);
    }

    /// <summary>
    /// The Department Data Access
    /// </summary>
    public class DepartmentAccess : IDepartmentAccess
    {
        CompanyEntities ctx;
        public DepartmentAccess()
        {
            ctx = new CompanyEntities(); 
        }
        /// <summary>
        /// Get All Departments
        /// </summary>
        /// <returns></returns>
        public List<Department> GetDepartments()
        {
            var depts = ctx.Departments.ToList();
            return depts;
        }
        /// <summary>
        /// Get Department base on Id
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public Department GetDepartment(int id)
        {
            var dept = ctx.Departments.Find(id);
            return dept;
        }
        /// <summary>
        /// Create Department
        /// </summary>
        /// <param name="dept"></param>
        public void CreateDepartment(Department dept)
        {
            ctx.Departments.Add(dept);
            ctx.SaveChanges();
        }
    }
}

The above class file contains DepartmentAccess class implementing IDepartmentAccess interface. The class contains the following methods:

  • GetDepartments() - Retrieves all departments from database using EF.
  • GetDepartment() - Retrieves department based on the id.
  • CreateDepartment() - Create a new Department in Department table.

The above class represents Model layer for our application.

Step 4: In the Controllers folder, add a new MVC controller of the name DepartmentController. In this controller add the following code:

using System.Web.Mvc;

using MVC5_Testing_1.Models;
using MVC5_Testing_1.ModelAccess;

namespace MVC5_Testing_1.Controllers
{
    public class DepartmentController : Controller
    {

        DepartmentAccess objds;

        public DepartmentController()
        {
            objds = new DepartmentAccess(); 
        }

        // GET: Department
        public ActionResult Index()
        {
            var Depts = objds.GetDepartments();
            return View("Index",Depts);
        }

         

        // GET: Department/Create
        public ActionResult Create()
        {
            var Dept = new Department();
            return View(Dept);
        }

        // POST: Department/Create
        [HttpPost]
        public ActionResult Create(Department dept)
        {
            try
            {
                objds.CreateDepartment(dept);
                return RedirectToAction("Index");
            }
            catch
            {
                return View(dept);
            }
        }
          
    }
}

The above controller class calls the DepartmentDataAccess class to retrieve all Departments and create a new Department. By using the Index and Create methods in the above controller, scaffold Index.cshtml and Create.cshtml views.

Run the application and make sure that these views get executed successfully.

Creating Test Projects

In this section, we will add a new class library project in the same solution. In this class library project, we will add a reference of our MVC project and using NuGet Package Manager, we will add NUnit. As explained in the previous article, NUnit is a Unit Testing framework for all .NET languages and brings in a xUnit style of testing. It provides several attributes which can be used during tests.

Step 1: In the solution, add a new class library project of the name ‘ControllerTests’. In this library, add a reference to the MVC project. Using NuGet Package Manager, add NUnit Framework in the current project as shown in the following figure.

nunit-nuget

Step 2: Since we are testing the MVC Controller, we need to get access to the MVC core objects, e.g. ViewResult, RouteValues, Controller etc. To access these objects in Test project, we need to add Microsoft.ASPNET.MVC NuGet Package in the test project. This can be done using NuGet Window or the package manager console as shown in the following figure:

mvc-package

The Controller makes a call to DepartmentDataAccess, which further makes a call to database using EntityFramework so we need to make install NuGet Package for EntityFramework as shown in the following figure

entity-framework-package

We need to make use of RouteValues to test the Redirect functionality from the controller action method. This is the object of type RouteValueDictionary defined in System.Web. So we need to add a reference to System.Web in our test project.

Step 3: In the ControllerText project, rename Class1.cs to ControllerTestClass.cs. In this class, add the following namespaces:

using NUnit.Framework;
using MVC5_Testing_1.Controllers;
using System.Web.Mvc;
using MVC5_Testing_1.Models;

Step 4: Testing Action method returning specific View

The Department Controller has an Index () action method which returns ‘Index’ view. So lets’ add the following method in the ControllerTestClass class.

[TestFixture]
public class ControllerTestClass
{
    /// <summary>
    /// Test the Action metjod returning Specific Index View
    /// </summary>
    [Test]
    public void TestDepartmentIndex()
    {
        var obj =new DepartmentController();

        var actResult = obj.Index() as ViewResult;

        Assert.That(actResult.ViewName, Is.EqualTo("Index"));
    }
}

The above class is applied with the TestFixture attribute, this is provides by NUnit framework, this set the behavior of the class as the class containing test methods. The method TestDepartmentIndex () is applied with the Test attribute. This informs the Test Runner to run the method as test.

The TestDepartmentIndex () method create an object of the Department Controller class. Using this object the Index () method is called which returns ViewResult. The test is verified using Assert object which checks the equality for the ViewName returned by the result to ‘Index’. If the result is returned as Index then the test will be passed else fail.

Build the Project and run the test from the Test Explorer, the result will be displayed as following:

controller-test

Step 5: Testing Action Method Returning RedirectToAction

The DepartmentController contains a Create() action method with HttpPost attribute applied on it. If this method gets executed successfully, the response will redirect to the Index action method. This will redirect to Index View. In the ControllerTestClass, add the following test method.

/// <summary>
/// Testing the RedirectToRoute to Check for the Redirect
/// to Index Action
/// </summary>
[Test]
public void TestDepartmentCreateRedirect()
{
    var obj = new DepartmentController();

    RedirectToRouteResult result = obj.Create(new Department()
    {
      DeptNo=190,Dname="D1",Location="L1"
    }) as RedirectToRouteResult;


    Assert.That(result.RouteValues["action"], Is.EqualTo("Index"));
   
}

The above method defines an object of DepartmentController. The Create () method is called which returns RedirectToRouteResult. This object represents the result that performs redirection based upon the model-state. This means that if Create () executes successfully, the Index will be returned, so MVC internally generates request for the Index () action method. This request can be captured using RouteValues dictionary. The above code uses RouteValues [“action”] and checks if this is equal to Index, if yes then the test passes, else it fails. Run the test and the result will be as shown in following figure

test-redirect

Step 6: Testing action method returning View based on the Model State

The Create Action method in DepartmentController accepts the Department object and saves the values from Department object into the Database. If this Create () action method successfully saves data in database, it returns Index (); else if it fires an exception, then it returns an Error View. This means that the Create () action method has its return based on the Model state. We can write the test for this method in the ControllerTestClass as shown in the following code:

/// <summary>
/// Test to return Error View is the Model is Invalid
/// </summary>
[Test]
public void TestDepartmentCreateErrorView()
{
    var obj = new DepartmentController();

    ViewResult result = obj.Create(new Department()
    {
        DeptNo = 2,
        Dname = "D1",
        Location = "L1"
    }) as ViewResult;

    Assert.That(result.ViewName, Is.EqualTo("Error"));
}

The above test method makes a call to the Create() method by passing Department object. If the Create method fires an exception, the Error View will be returned and the Test will be successful. Test the above method and the result will be displayed as shown in the following figure:

test-error-view

Conclusion: In MVC applications Controller action methods contains various types of logic and based on the ModelState, the return from these action methods may vary. In this case it is challenging to write tests. Using NUnit and carefully understanding each action method, we can write test methods to make sure the controller is behaving correctly.

Download the entire source code of this article (Github)

This article has been editorially reviewed by Suprotim Agarwal.

Absolutely Awesome Book on C# and .NET

C# and .NET have been around for a very long time, but their constant growth means there’s always more to learn.

We at DotNetCurry are very excited to announce The Absolutely Awesome Book on C# and .NET. This is a 500 pages concise technical eBook available in PDF, ePub (iPad), and Mobi (Kindle).

Organized around concepts, this Book aims to provide a concise, yet solid foundation in C# and .NET, covering C# 6.0, C# 7.0 and .NET Core, with chapters on the latest .NET Core 3.0, .NET Standard and C# 8.0 (final release) too. Use these concepts to deepen your existing knowledge of C# and .NET, to have a solid grasp of the latest in C# and .NET OR to crack your next .NET Interview.

Click here to Explore the Table of Contents or Download Sample Chapters!

What Others Are Reading!
Was this article worth reading? Share it with fellow developers too. Thanks!
Share on LinkedIn
Share on Google+

Author
Mahesh Sabnis is a DotNetCurry author and a Microsoft MVP having over two decades of experience in IT education and development. He is a Microsoft Certified Trainer (MCT) since 2005 and has conducted various Corporate Training programs for .NET Technologies (all versions), and Front-end technologies like Angular and React. Follow him on twitter @maheshdotnet or connect with him on LinkedIn


Page copy protected against web site content infringement 	by Copyscape




Feedback - Leave us some adulation, criticism and everything in between!