1. Understanding MVC pattern
In high-level terms, MVC pattern means that application will be split into three pieces:
(1) Model, which contains the data users work with. It can be viewmodel, represents the data being transferred between controller and view. Or it can be domain model, which contains the data in a business domain.
(2) Views, which are used to render some part of the model to the user
(3) Controllers, process incoming request, perform operations on model, and then select views to render to the user.
1.1 Understanding the domain model
The most important part of MVC application is the domain model. It is the single, authoritative definition of the business data and processes within your application.
A common way of enforcing the separation of the domain model from the rest of asp.net MVC application is to place the model in a separate C# assembly.
1.2 ASP.NET MVC
In ASP.NET MVC, controllers are classes, usually derived from System.Web.Mvc.Controller class. Each public method in controller class is an action method, that is associated with a configuration URL through the routing system.
When a request is send to the URL associated with an action method, the statements in the controller class are executed in order to perform some operation on the domain model and then select a view to display to the client.
2. Building loosely coupled components
One of most important features of the MVC pattern is that it enables the separation of concerns. In an ideal situation, each component knows nothing about any other component and only deal with other areas of the application through abstract interfaces. This is known loose coupling.
2.1 Using dependecy injection
Dependency injection is a design pattern that completes the loose coupling process. There are normally two parts to the DI pattern. The first is that I remove any dependencies on concrete classes from my component. We can achieve this by creating class constructor that accepts implementations of the interfaces I need as argument.
1 public class HomeController : Controller 2 { 3 private IEmailSender emailSender; 4 5 public HomeController(IEmailSender emailSenderParam) 6 { 7 emailSender = emailSenderParam; 8 } 9 }
In this way, HomeController has no idea how we implement IEmailSender, It only depends on the IEmailSender interface.
The second part is to inject dependencies declared by HomeController when I create instances of it. The dependencies are injected into homeController at runtime. That is to say, an instance of some class that implement IEmailSender will be created and pass to HomeController constructor.
And you don‘t have to figure the process by yourself, the heavy job is done by IoC container, which is a component that acts as a broker. There are some good opensource DI container out therer, such as Ninject, AutoFac.
3. Getting started with automated testing
In ASP.NET MVC, it is designed to make it as easy as possible to set up automated tests and use development methologies such as TDD. In general, we focus on two types of automated testing. The first one is unit testing, which is a way to specify and verify the behavior of individual classes in isolation from the rest of the application. The second is integration testing, which is a way to specify and verify the behavior of multiple components working together.
3.1 Unit Testing
A test fixture is a c# class that defines a set of methods: one method for each behavior you want to verify.
1 [TestClass] 2 public class AdminControllerTest 3 { 4 [TestMethod] 5 public void ChangeLoginName() 6 { 7 //arrage 8 var user = new User() {LoginName = "Bob"}; 9 var repository = new FakeRepository(); 10 repository.Add(user); 11 var target = new AdminController(repository); 12 var oldLoginName = user.LoginName; 13 var newLoginName = "Joe"; 14 15 //act 16 target.ChangeLoginName(oldLoginName, newLoginName); 17 18 //assert 19 Assert.AreEqual(newLoginName, user.LoginName); 20 Assert.IsTrue(repository.DidSubmitChanges); 21 } 22 }
The test fixture is the CanChangeLoginName method, and it is decorated with the TestMethod attribute. The method follows a pattern known as arrage/act/assert. Arrange refers to setting up the conditions for the test, act refers to performing the test and assert refers to verifying the result.
3.2 Using TDD and red-green-refactor workflow
With Test driven development, you use unit test to help you design your code. It works like this:
(1) Determine you need to add new feature or method to your application
(2) Write the test that will validate the behavior of the new feature when it is written
(3) run the test a get a red light
(4) Write the code to implement the new feature
(5) Run the test again and correct the code until you get a green light
(6) Refactor the code if it is required
(7) Run the test again.
This workflow is repeated for every feature you add.
3.3 Integration test
For web application, the most common approach to integration testing is UI automation, means simulating or automating a web browser to exercise the applicaiton‘s entire technology stack by reproducing the actions that a user would perform. The two best-known open source browser automation options for .net developers are:
Selenium RC and WatiN