Notes on Unit Testing in C# with ASP.NET MVC using NUnit, Moq and Selenium

2014-11-06 14:38

Some quick notes on unit testing and testing ASP.NET MVC projects.

Tools

The environment and tools used:

Add Unit Testing to a Project

  1. Install the NUnit extension in Visual Studio
  2. Add test project (use the Class Library template) to solution
  3. Write test case using NUnit and Moq

Example TestCase with NUnit

A minimal test case is shown here. Setup and TearDown methods are only included to show where to create and destroy objects that is of use in more then one test method.

using NUnit.Framework;
using System.Web.Mvc;
using WebApplicationNUnitAndSelenium.Controllers;

namespace NUnitTestDemo
{
    [TestFixture]
    class Demo
    {
        [SetUp]
        public void Setup() {}

        [TearDown]
        public void TearDown(){}

        [Test]
        public void IndexTest()
        {
            var controller = new HomeController();

            var result = controller.Index() as ViewResult;

            Assert.IsNotNull(result);
            Assert.IsInstanceOf(typeof(HomeController.SomeViewModel), result.Model);
            Assert.AreEqual("Some message", result.ViewData["Message"]);
        }
    }
}

Start Using Selenium

  1. Install Selenium IDE extension in Firefox
  2. Record test case

Use Selenium with NUnit in Visual Studio:

  1. Use NuGet to add "Selenium Webdriver" to the test project
  2. Use NuGet to add "Selenium Webdriver Support Classes" to the test project

Setup Selenium with InternetExplorer and Chrome (optional)

  1. Download IE Webdriver from the Selenium download page (choose the appropriate 32 or 64 bit version) and unzip.
  2. Righ-click on the project name and click "Add existing item..."
  3. Browse to the folder containing IEDriverServer.exe and choose that file to add to the project
  4. Under the project tree right-click on the file and click Properties
  5. Set the value of the field "Copy to Output Directory" to "Copy if newer"

Repeat the same process with the Webdriver for Chrome.

Example TestCase using Selenium

The following example shows a NUnit test case that runs all three browsers. The driver attribute is reset with the appropriate driver for each run. Remove the references to OpenQA.Selenium.Chrome and OpenQA.Selenium.IE if you skipped to install the webdrivers for them.

The driver could also be created in the test SetUp method and then call Quit() in the TearDown method. This is suitable for running multiple test case using the same driver.

using NUnit.Framework;
using OpenQA.Selenium;
using OpenQA.Selenium.Chrome;
using OpenQA.Selenium.Firefox;
using OpenQA.Selenium.IE;
using OpenQA.Selenium.Support.UI;
using System;

namespace NUnitTestDemo
{
    [TestFixture]
    public class SeleniumTests
    {
        IWebDriver driver;

        [Test]
        public void FxGoogleSearch()
        {
            driver = new FirefoxDriver();
            GoogleSearch();
            driver.Quit();
        }

        [Test]
        public void IeGoogleSearch()
        {
            driver = new InternetExplorerDriver();
            GoogleSearch();
            driver.Quit();
        }

        [Test]
        public void ChromeGoogleSearch()
        {
            driver = new ChromeDriver();
            GoogleSearch();
            driver.Quit();
        }

        public void GoogleSearch()
        {
            //Navigate to the site
            driver.Navigate().GoToUrl("http://www.google.com");

            // Find the text input element by its name
            IWebElement query = driver.FindElement(By.Name("q"));

            // Enter something to search for
            query.SendKeys("Selenium");

            // Now submit the form
            query.Submit();

            // Google's search is rendered dynamically with JavaScript.
            // Wait for the page to load, timeout after 5 seconds
            WebDriverWait wait = new WebDriverWait(driver, TimeSpan.FromSeconds(5));
            wait.Until((d) => { return d.Title.StartsWith("Selenium"); });

            //Check that the Title is what we are expecting
            Assert.IsTrue(driver.Title.StartsWith("Selenium - "));
        }
    }
}

Make Use of Moq

Moq is used to create mockups to make unit testing easier. Mockups are phony objects pretending to be of a certain type. This is used to compartmentalize the unit test.

Take a look at Moq Quickstart to get an idea of how to use this.

Comments

It is quite easy to create unit tests and to use Selenium. It get's trickier to test more complicated components and/or when you need a lot of mockups to make a component testable.

Testing ASP.NET MVC controllers can get very complicated and involve a lot of mockups. Since tests are closly coupled with the code this should be visible in the project layout. Put data access layer test code in the data access layer, web frontend testing code with the web frontend and so on.

It is also good practice in general to setup and teardown the database as part of tests. This makes it easy to automate your tests for continous integration (CI) while also making it easy for new developers to setup the database in their development environment.

Among additional tools to improve testing and development the following could be mentioned:

  • QUnit - a JavaScript Unit Testing Framework
  • Vagrant - for creating reproducible development environments

The direction of ASP.NET vNext and Entity Framework (see EF7 - New Platforms, New Data Stores) will contribute a lot to the testability and overall usability of the ASP.NET framework.

Resources