Wednesday, November 23, 2011

ASP.NET MVC3 Validation Basic

Introduction

The ASP.NET MVC3 comes with a validation feature that not only supports both server side and client side validation, but also hides all validation details to have a very clean controller code and HTML markup.

Validation Walkthrough

The easiest way to try ASP.NET MVC validation feature is to create a web application with the default internet application template that will automatically generate all essential validation code in it.
Validation Attribute on Model Class
Let’s take a look at the validation code generated for RegisterModel class.
public class RegisterModel
{
    [Required]
    [Display(Name = "User name")]
    public string UserName { get; set; }

    [Required]
    [DataType(DataType.EmailAddress)]
    [Display(Name = "Email address")]
    public string Email { get; set; }

    [Required]
    [ValidatePasswordLength]
    [DataType(DataType.Password)]
    [Display(Name = "Password")]
    public string Password { get; set; }

    [DataType(DataType.Password)]
    [Display(Name = "Confirm password")]
    [Compare("Password", ErrorMessage = "The password and confirmation password 
  do not match.")]
    public string ConfirmPassword { get; set; }
}
  • The Required attribute is used on property UserNameEmail and Password to mark them as required.
  • The Display attribute is used on all properties to give them a display name as field label or in error message.
  • The DataType attribute is used on property Email and Password to indicate type of property.
  • The ValidationPasswordLength attribute is a custom validation attribute. I will talk more about it later.
  • The Compare attribute is used on ConfirmPassword to compare Password with ConfirmPassword.
Where is Validation Attribute from?
The general purpose validation attributes are defined in System.ComponentModel.DataAnnotations namespace (System.ComponentModel.DataAnnotations.dll). This includes Required attribute, Range attribute,RegularExpression attribute, StringLength attribute, etc. They all inherit from ValidationAttributebase class and override IsValid method to provide their specific validation logic. DisplayAttribute is also inSystem.ComponentMode.DataAnnotations namespace, but it’s a display attribute instead of validation attribute. DataTypeAttribute is a validation attribute, but is classified as display attribute in MSDN. FYI, inSystem.ComponentMode.DataAnnotations namespace, there are Data Modeling attributes,AssociationAttributeKeyAttribute, etc. designed for Entity Framework.
RequiredAttributeClass.gif
CompareAttribute is a special purpose validation attribute provided by ASP.NET MVC. It is in System.Web.Mvcnamespace (System.Web.Mvc.dll). Another validation attribute provided by ASP.NET MVC is RemoteAttribute that uses Ajax call to service side controller action to do validation. The CompareAttribute also implementsIClientValidatable, an interface of ASP.NET MVC client validation. The IClientValidatable has only one method GetClientValidationRule that has the following signature:
IEnumerable<modelclientvalidationrule> GetClientValidationRules
(ModelMetadata metadata, ControllerContext context);
</modelclientvalidationrule>
  • ModelMetadata is a container for common metadata. It allows classes to utilize model information when doing validation
  • ControllerContext is a container for HTTP request and other request environment data.
  • ModelClientValidationRule is a base class for client validation rule that is sent to the browser. There are six built-in validation rules in MVC: ModelClientValidationEqualToRule,ModelClientValidationRemoteRuleModelClientValidationRequiredRule,ModelClientValidationRangeRuleModelClientValidationStringLengthRule,ModelClientValidationRegexRule. If you pay attention, you can see all general purpose validation attributes in System.ComponentModel.DataAnnotations have a correspondingModelClientValidationRule in here. The ASP.NET MVC creates adapter, e.g.RequiredAttributeAdapter, to extend general purpose validation attribute to support ASP.NET MVC validation design.
CompareAttributeClass.gif
ValidatePasswordLengthAttribute is a custom validation that inherits from ValidateAttribute and implements IClientValidatable.
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property, 
  AllowMultiple = false, Inherited = true)]
    public sealed class ValidatePasswordLengthAttribute : ValidationAttribute, 
  IClientValidatable
    {
        private const string _defaultErrorMessage = "'{0}' 
   must be at least {1} characters long.";
        private readonly int _minCharacters = 
  Membership.Provider.MinRequiredPasswordLength;

        public ValidatePasswordLengthAttribute()
            : base(_defaultErrorMessage)
        {
        }

        public override string FormatErrorMessage(string name)
        {
            return String.Format(CultureInfo.CurrentCulture, ErrorMessageString,
                name, _minCharacters);
        }

        public override bool IsValid(object value)
        {
            string valueAsString = value as string;
            return (valueAsString != null && valueAsString.Length >= _minCharacters);
        }

        public IEnumerable<modelclientvalidationrule> 
 GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
        {
            return new[]{
                new ModelClientValidationStringLengthRule(FormatErrorMessage
  (metadata.GetDisplayName()), _minCharacters, int.MaxValue)
            };
        }
    }
</modelclientvalidationrule>
One note in here is the ValidatePasswordLengthAttribute has reference to Membership, so the application needs to have configuration of Membership provider in place to make it work.
ValidatePasswordLengthAttributeClass.gif
You can apply different validation attributes on a single property, this aggregate design makes ASP.NET MVC validation feature more powerful and flexible.
Server Side Validation
In order to see how our custom validation comes into play in ASP.NET MVC server side, let’s take a look at the call stack to IsValid method of custom validation attribute - ValidatePasswordLengthAttribute.
CallStack.gif
From the call stack, you can see the server side validating is happening during model binding step (DefaultModelBinder.BindModel(…)). The ModelValidator calls each validation attribute class to validate the model data based on a given setting. The validation results (ModelValidationResult) are stored inModelState to be used in action or view.
[HttpPost]
public ActionResult Register(RegisterModel model)
{
    if (ModelState.IsValid)
    {
        // Attempt to register the user
        MembershipCreateStatus createStatus = MembershipService.CreateUser
   (model.UserName, model.Password, model.Email);

        if (createStatus == MembershipCreateStatus.Success)
        {
            FormsService.SignIn(model.UserName, false /* createPersistentCookie */);
            return RedirectToAction("Index", "Home");
        }
        else
        {
            ModelState.AddModelError("", 
  AccountValidation.ErrorCodeToString(createStatus));
        }
    }

    // If we got this far, something failed, redisplay form
    ViewBag.PasswordLength = MembershipService.MinPasswordLength;
    return View(model);
}
The ModelState.IsValid returns true or false from checking internal errors collection.
public bool IsValid
{
    get
    {
        return this.Values.All((ModelState modelState) => modelState.Errors.Count == 0);
    }
}
Client Side Validation
The client side validation is enabled by default in web.config.
<appSettings>
    <add key="ClientValidationEnabled" value="true"/> 
    <add key="UnobtrusiveJavaScriptEnabled" value="true"/> 
  </appSettings>
However, you must make sure jquery.validation.min.js and jquery.validation.unobtrusive.min.js are added in the view page also.
<script src="@Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript">
</script>
<script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" 
type="text/javascript"></script>
The extension methods for HtmlHelper class are required for validation: ValidateValidateFor,ValidationMessageValidationMessageForValidationSummary.
The jquery.validate.min.js is standard jQuery validation library. The jquery.validate.unobtrusive.min.js is an ASP.NET MVC client side validation library that is built on top of jQuery validation library. It uses HTML element attributes to store validation information. This design is very clean and intrusive to the UI designer.

Remote Validation Attribute in Action

The above validation code is generated from ASP.NET MVC project template. I also want to show Remote Validation Attribute here to show how to use it. The requirement is very simple - UserName “Bin” is not allow in the application, the application needs to show error right after entered “Bin” in User Name textbox.
  1. Add Remote attribute on UserName of LogOnModel.
    [Required]
    [Display(Name = "User name")]
    [Remote("DisallowName", "Account")]
    public string UserName { get; set; }
    The first parameter is Action name, the second parameter is Controller name.
  2. Create a DisallowName action in AccountController.
    public ActionResult DisallowName(string UserName)
    {
        if (UserName != "Bin")
        {
            return Json(true, JsonRequestBehavior.AllowGet);
        }
    
        return Json(string.Format("{0} is invalid", UserName), 
       JsonRequestBehavior.AllowGet);
    }
    That is, a remote validation is done. Let’s take a look at what it looks like on screen:
    LogOnScreen.gif

Conclusion

The validation design in ASP.NET MVC3 is very clean and powerful. It makes server and client side validation consistent.

Using the Code

The code is developed in Visual Studio 2010. There is no special requirement for using the code.

ASP.NET MVC3 Forms Authentication

Motivation

The default ASP.NET MVC Internet Application comes with forms authentication. It has all layers and classes in a single project. This is good for a simple and small application, but for an enterprise application, I would like to have a better architecture. So, I changed the default Internet Application to have more layers and put the layers in separate projects.

Analysis

In order to re-architecture this default application, I need to use the DDD (Domain Driven Design) concept to find the domain and services first. Because the core functionality in this application is authenticating users with forms authentication, the domain is membership management. The membership management is actually implemented inAspNetSqlMembershipProvider which is the realization of Microsoft’s Provider pattern, so the Domain is actually hiding behind the scenes. What are ChangePasswordModelLogOnModel, and RegisterModel, you may ask? First of all, they are Models, but they are View Models instead of Domain Models, from my perspective. Domain model is the core of your application and should contain both the data and behavior to reflect the specific domain.ChangePasswordModelLogOnModel, and RegisterModel really just help move data from the View to the Domain and vice versa. After identifying the domain, I am able to decide what should stay in the default project and what should be moved to a different project to have a better separation of concern, reusability, and testability.

Change

The below steps are used to change the default application to a different architecture.
Step 1: Create View Models
Like I mentioned above, ChangePasswordModelLogOnModel, and RegisterModel are actually View Models from my perspective. So, I created a ViewModels folder in the default project and createdChangePasswordViewModelLogOnViewModel, and RegisterViewModel in it. All the places that usedChangePasswordModelLogOnModel, and RegisterModel originally are refactored to useChangePasswordViewModelLogOnViewModel, and RegisterViewModel.
Step 2: Create Utilities
There is an AccountValidation class in the default application that is used to convertMembershipCreateStatus to a description for displaying in the view. I created a Utilities folder to contain it. This folder will contain all the common classes and helper classes. Therefore, ValidatePasswordLengthAttributes is moved into it also.
Step 3: Create Server Interfaces
The default application already has a good decoupling for Membership and Forms Authentication functions to allow switching implementation in different environments, like in Tests project, MockMembershipService is used instead of AspNetSqlMembershipProvider to allow testing logon, register, etc., functions without connecting to the membership repository. However, I like to only keep the service interface in the web project. A ServiceInterfacesfolder is created and IFormAuthenticationService and IMembershipService are moved into it.
Step 4: Create Security Project
From step 3, you will know I like the implementation to stay in a separate project (assembly) to better decouple them from the contract and the caller. The Demo.Web.Secruity project is created and AccountMembershipService andFormAuthenticationService are moved into it. There is a problem. The AccountController createsAccountMembershipService and FormAuthenticationSerrvice instances directly to provide for using in the controller actions. I don’t want to let the Web project reference the Security project and seeing the concrete classes because this ruins the separation of concern. This problem will be fixed in the following steps with Dependency Injection.
Step 5: Create Library
Before I can have Dependency Injection in place, I need to have some cornerstone first. The IoC container I use in here is Unity. It’s not the best IoC container on the market, but it has all the features I need, like lifetime management, configuration file, etc. I created a Library folder in the folder of the solution file and copied all the Unity assembly files into it.
LibraryFolder.gif
LibraryFolderContent.gif
In order to let the solution manage all the Unity files, I also created a Library solution folder and made references to all files in the Library folder.
LibrarySolutionFolder.gif
Step 6: Create Base Project
For an enterprise application, there are always some utility and helper classes that need to be used in all projects. The Demo.Base project is created to contain those classes. So far, I only have one interface IDependencyLocatorin it that is implemented in the project that has a dependency injection access point.
Step 7: Create Dependency Injection
ASP.NET MVC3 has built-in Dependency Injection support (DependencyResolver), but I prefer to manage Dependency Injection via a Registry class. A WebRegistry class is created in the Web project. It hasDependencyLocator to wrap up the IoC container. The FormsService property and MembershipServiceproperty will query the IoC container to get the instance object.
WebRegistryClass.gif
UnityDependencyLocatorClass.gif
The UnityDependencyLocator binds with WebRegistry in Global.asax.cs.
protected void Application_Start()
{
    AreaRegistration.RegisterAllAreas();

    RegisterGlobalFilters(GlobalFilters.Filters);
    RegisterRoutes(RouteTable.Routes);

    RegisterUnityContainer();
}

private void RegisterUnityContainer()
{
    var container = new UnityContainer();
    UnityConfigurationSection section = (UnityConfigurationSection)
           ConfigurationManager.GetSection("unity");
    section.Configure(container);
    WebRegistry.DependencyLocator = new UnityDependencyLocator(container);
}
The dependency configuration is in the web.config:
<configSections>
    <section name="unity" 
      type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, 
            Microsoft.Practices.Unity.Configuration" />
</configSections>

<unity xmlns="http://schemas.microsoft.com/practices/2010/unity">
    <alias alias="IMembershipService" 
      type="Demo.Web.ServiceInterfaces.IMembershipService, Demo.Web" />
    <alias alias="MembershipService" 
      type="Demo.Web.Security.AccountMembershipService, Demo.Web.Security" />
    <alias alias="IFormsAuthenticationService" 
      type="Demo.Web.ServiceInterfaces.IFormsAuthenticationService, Demo.Web" />
    <alias alias="FormsAuthenticationService" 
      type="Demo.Web.Security.FormsAuthenticationService, Demo.Web.Security" />
    <container>
      <register type="IMembershipService" mapTo="MembershipService">
        <constructor />
      </register>
      <register type="IFormsAuthenticationService" mapTo="FormsAuthenticationService" />
    </container>
</unity>
The AccountController is changed to initialize the FormsService and MembershipService variables withWebRegistry.
protected override void Initialize(RequestContext requestContext)
{
    if (FormsService == null) { FormsService = WebRegistry.FormsService; }
    if (MembershipService == null) { MembershipService = WebRegistry.MembershipService; }

    base.Initialize(requestContext);
}
One more thing needs to be done here, which is to add:
xcopy /Y /F "$(SolutionDir)Demo.Web.Security\$(OutDir)\
            "Demo.Web.Security.dll "$(SolutionDir)Demo.Web\bin"
in the Security project “Build Events -> Post-build event command line” to copy Demo.Web.Security.dll into the Web application’s bin folder because there is no direct reference between the Web project and the Security project. The IoC container needs the assembly file to bind the implementation to the interface.
Step 8: Clean up
Finally, I have all the pieces here, I just need to remove the original Models folder from the Web project and refactor the entire solution to replace the old classes with the new classes and layers.

Comparison

After the change, the View, ViewModel, Controller, and Service interface are still in the Web project. The Model layer is in AspNetSqlMembershipProvider. The Service implementation is in the Security project.
Before the change:
SolutionBeforeChange.gif
After the change:
SolutionAfterChange.gif

Conclusion

What I did in this article is just to reflect my thoughts on how a web application with Forms Authentication should be organized. There is no big innovation. It’s just a different idea on developing an application with ASP.NET MVC that has Forms Authentication for entitlement management.

Using the Code

The code is developed in Visual Studio 2010. SQL Server database aspnetdb is needed for membership that can be created with aspnet_regsql.exe.

Developing Web Applications with ASP.NET MVC3 and Entity Framework 4.1

Download source code - 754.12 KB

Introduction

ASP.NET MVC and Entity Framework is a good combination for a web application that has database backend on Microsoft platform. In this article, I will provide a demo application that is developed with the ASP.NET MVC3 and Entity Framework 4.1. The demo also adopts the following design principal, pattern and best practice to make it more flexible and extensible.
  • Separation of Concerns
  • POCO
  • Code-First
  • Registry Pattern
  • Repository Pattern
  • Persistence Ignorance
  • Dependency Injection
  • Unit Testing
In order to open and run the demo application, you need to have SQL Server/SQL Server Express with Northwind sample database and Visual Studio 2010 with ASP.NET MVC3 and Entity Framework 4.1.

Demo Application Architecture

ASP.NET MVC already has very good defined layers. In my demo, I move Model layer into its own assembly to allow reusable in other applications. Also, the model is a rich model that not just contains data and behaviors, also gets more responsibility via services. The application architecture is like this:
Architecture.gif
  • Demo.Web package contains ASP.NET MVC Views and Controllers
  • Demo.Web.Tests package contains test case for Controllers
  • Demo.Models package contains domain model, business model, and data interfaces
  • Demo.Data package contains data access logic with Entity Framework
  • Demo.Base package contains utilities for the entire application

Design Principal, Pattern, and Best Practice

I will not go through every detail of my demo application. The source code shows the complete picture. I will only focus on those design principals, patterns, and best practices used in here.

Separation of Concerns

The ASP.NET MVC already follows Separation of Concern principal pretty good, it puts UI into View layer, interaction into Controller layer, and domain entities into Model layer. The only improvement I made in this demo application is to further moving Model layer into a separate assembly and has a Data layer to contain data access logics with Entity Framework.
SeperationOfConcerns.gif

POCO

I use Visual Studio 2010 Extension Manager installed ADO.NET C# POCO Entity Generator generated my original POCO domain entity Customer and Order based on Entity Data Model (edmx). The code generated is default in Data layer, I moved them from Data layer into Model layer and completely removed code generator template files. The domain entity will be enhanced and modified manually since that except there are some major table structure changes.
CustomerClass.gif
public partial class Customer
{
 #region Primitive Properties

 public virtual string CustomerID
 {
  get;
  set;
 }

 [Required]
 public virtual string CompanyName
 {
  get;
  set;
 }

 public virtual string ContactName
 {
  get;
  set;
 }

 public virtual string ContactTitle
 {
  get;
  set;
 }

 public virtual string Address
 {
  get;
  set;
 }

 public virtual string City
 {
  get;
  set;
 }

 public virtual string Region
 {
  get;
  set;
 }

 public virtual string PostalCode
 {
  get;
  set;
 }

 public virtual string Country
 {
  get;
  set;
 }

 public virtual string Phone
 {
  get;
  set;
 }

 public virtual string Fax
 {
  get;
  set;
 }

 #endregion
 #region Navigation Properties

 public virtual ICollection<Order> Orders
 {
  get
  {
   if (_orders == null)
   {
    var newCollection = new FixupCollection<Order>();
    newCollection.CollectionChanged += FixupOrders;
    _orders = newCollection;
   }
   return _orders;
  }
  set
  {
   if (!ReferenceEquals(_orders, value))
   {
    var previousValue = _orders as FixupCollection<Order>;
    if (previousValue != null)
    {
     previousValue.CollectionChanged -= 
        FixupOrders;
    }
    _orders = value;
    var newValue = value as FixupCollection<Order>;
    if (newValue != null)
    {
     newValue.CollectionChanged += FixupOrders;
    }
   }
  }
 }
 private ICollection<Order> _orders;

 #endregion
 #region Association Fixup

 private void FixupOrders(object sender, NotifyCollectionChangedEventArgs e)
 {
  if (e.NewItems != null)
  {
   foreach (Order item in e.NewItems)
   {
    item.Customer = this;
   }
  }

  if (e.OldItems != null)
  {
   foreach (Order item in e.OldItems)
   {
    if (ReferenceEquals(item.Customer, this))
    {
     item.Customer = null;
    }
   }
  }
 }

 #endregion
}

Code-First

Code-First in Entity Framework is different with Model-First and Database-First. Honestly, I follow the Code-First philosophy without use exact Code-First steps to setup project in the beginning. Instead, I created Entity Data Model from database, then use it to generate the original domain entity code and moved the code into model layer. So, the Code-First approach is just to allow me to isolate future domain entity code changes with database changes completely.

Registry Pattern

Model layer has a special public static object Registry that is a well-known object to let other objects using it find common objects and services. This is an implementation of Registry pattern in Pattern of Enterprise Application Architecture (PoEAA) book. In my demo application, Registry object allows domain entities and upper layers to locate Repository service - Context and RepositoryFactory.
RegistryClass.gif
public static class Registry
{
 public static IDependencyLocator DependencyLocator;

 public static IContext Context
 {
  get
  {
   return DependencyLocator.LocateDependency<IContext>();
  }
 }
 
 public static IRepositoryFactory RepositoryFactory
 {
  get
  {
   return DependencyLocator.LocateDependency
      <IRepositoryFactory>();
  }
 }
} 

Repository Pattern

In Hibernate application, there is a pattern called Data Access Object (DAO) pattern, the Repository Pattern is the counterpart pattern with a different name in Entity Framework. I read Repository Pattern implementation code inNerdDinner, it is not separating data access logic to its own layer good enough. In my demo, Repository Interfaces all reside in Model layer to provide data service access point, then use Dependence Injection to inject specific Data layer implementation into Model layer. The reason for this kind of implementation is to promote Model centric idea and allow switching Data layer for different implementation or Unit Test.
RepositoryInterfaces.gif
RepositoryClasses.gif

Persistence Ignorance

Define data access interfaces in Model layer and put Data layer into its own assembly encourage Persistence Ignorance here, Model layer and upper layers don’t really need to worry about how the model gets loaded, updated, or saved by the data layer. Additionally, I can switch Data layer to different ORM framework, like NHibernate, or a Mock implementation whenever it is necessary.

Dependency Injection

Dependency Injection plays a crucial part in my demo. All services module need to be late bound with Model layer with Dependency Injection. In addition, the IoC container manages the lifetime of service objects. One example is theContext object. I set lifetime type as PerThreadLifetimeManager in Unity configuration. This makes one and only one context object created in a single request and the different request has a different context object. Another thing I want to mention is ASP.NET MVC3 has its own way to provide Dependency Inject for controller via implementing DependencyResolver interface. I tried it, but eventually not adopt it because my application is Model centric application, so Registry is a better place to locate all the services instead of controller constructor. The IoC container I used in the demo is Unity. The MEF IoC container is getting more popular at the moment, but it’s more intrusive to domain entities by using attribute and not allowing configurable dependencies that make me hesitate to use it.
protected void Application_Start()
{
 AreaRegistration.RegisterAllAreas();

 RegisterGlobalFilters(GlobalFilters.Filters);
 RegisterRoutes(RouteTable.Routes);

 RegisterUnityContainer();
}

private void RegisterUnityContainer()
{
 var container = new UnityContainer();
 UnityConfigurationSection section = 
   (UnityConfigurationSection)ConfigurationManager.GetSection("unity");
 section.Configure(container);
 Registry.DependencyLocator = new UnityDependencyLocator(container);
} 

Unit Test

I usually use Test Project to automatically integration test instead of pure unit test. The reason I do this is to allow the test be more close to user acceptance test to avoid thinking of every possible test scenario for each single class in my application. In this demo, the CustomerControllerTest will have test case Index to testCustomerController Index action. There is another project Demo.DataMock that is the mock of Data layer. I can use mock framework (e.g. MOQ) to mock Data layer in test case, but I decide to not use it because I don’t want a permanent mock for Data layer in test case, I want Data layer mock during development and build process, on the other hand, I also want my test can run against the real data layer before I check in my changes to make sure the test case can be all passed in the “production” environment. I understand running again the real database is slow, but keep in mind, with test being more close to real usage allows me to uncover more possible bugs and the running again of real database is just a one time thing for each check in or before release to QA.
Web.config in Demo.Web
<unity xmlns="http://schemas.microsoft.com/practices/2010/unity">
<alias alias="IContext" type="Demo.Models.DataInterfaces.IContext, Demo.Models" />
<alias alias="Context" type="Demo.Data.Context, Demo.Data" />
<alias alias="IRepositoryFactory" 
 type="Demo.Models.DataInterfaces.IRepositoryFactory, Demo.Models" />
<alias alias="RepositoryFactory" type="Demo.Data.RepositoryFactory, Demo.Data" />
<container>
  <register type="IContext" mapTo="Context">
 <lifetime type="PerThreadLifetimeManager" />
  </register>
  <register type="IRepositoryFactory" mapTo="RepositoryFactory">
 <constructor>
   <param name="context" />
 </constructor>        
  </register>
</container>
</unity>
App.config in Demo.Web.Tests
<unity xmlns="http://schemas.microsoft.com/practices/2010/unity">
<alias alias="IContext" type="Demo.Models.DataInterfaces.IContext, Demo.Models" />
<alias alias="Context" type="Demo.DataMock.Context, Demo.DataMock" />
<alias alias="IRepositoryFactory" 
 type="Demo.Models.DataInterfaces.IRepositoryFactory, Demo.Models" />
<alias alias="RepositoryFactory" type="Demo.DataMock.RepositoryFactory, Demo.DataMock" />
<container>
  <register type="IContext" mapTo="Context">
 <lifetime type="PerThreadLifetimeManager" />
  </register>
  <register type="IRepositoryFactory" mapTo="RepositoryFactory">
 <constructor>
   <param name="context" />
 </constructor>
  </register>
</container>
</unity>


Thursday, June 2, 2011

End-to-End Testing

In general, NUnit based unit test is used to test a single class or a single layer. We found this is very cumbersome and overkill in our development practice. Following are some problems we found with the unit test for a single class or a single layer:
  1. There are a lot of small tests need to be created.
  2. In order to test on a single class or single layer, you probably need to create many mock or stub classes to avoid intervention from other classes.
  3. Come up with all different test scenarios are time consuming and difficult. In order to write test for a single class, you need to image a lot of ways to consume that single class, so you need to consider all possible situations though they are not realistic.
  4. Refactoring could impact existing tests dramatically. The test is supposedly used to allow us can easily refactor our code without worry about breaking stuffs. However, when the test is too little and too focuses on single classes. It can be easily be broken by refactoring process. So, we need to spend significant amount of time to fix test or rethink scenarios.
  5. Difficult to coordinate with QA team. QA team usually comes up test scenarios from user perspective. Because there is no direct relationship between their tests scenarios to our detail tests, so it’s almost impossible to directly use their test plan to create test.

Base on all the problems we found, we actually uses NUnit creating end-to-end tests. Use a common web application as example. A web application usually has UI layer, Application layer, and Database layer. The UI layer usually has a thin UI Rendering layer and a UI Model layer, The Application layer usually has a Domain layer and a Data Access layer.


There are two layers not NUnit testable, UI Rendering layer and Database layer. So, the rest layers we should have good enough tests to cover all possible situations. The end-to-end test we used will only create test from UI Model layer to Domain layer, so we skipped the un-testable UI Rendering Layer and we create a Mock Data Access Layer to avoid requiring a real database.


By doing this, we get following benefits:
  1. No small tests all the places.
  2. Can easily coordinate with QA team and even directly use their test plan as the base of our test.
  3. Allow utilize refactoring to continue improve our design without worry about keep adding test.
By doing end-to-end test doesn’t mean we totally against test on single class or layer, we realize there are some situations require fine test case for single class or single layer to make sure the key functionality is completely covered.