If you don’t currently unit test your code, you might find the process awkward and
disruptive—more typing, more testing, more iterations. If you do perform unit tests, you already know what a difference it makes: fewer bugs, better-designed software, and fewer surprises when you make a change.
Going from a nontester to a tester can be tough. It means adopting a new habit and sticking with it long enough to get the benefits. Our first few attempts to embrace testing failed because of unexpected shifts in due dates. It’s hard to convince yourself that doing something that feels like extra work is worthwhile when time is tight.
We have both become adherents of unit testing and are convinced that it is a great style of development. ASP.NET MVC is an ideal candidate for adopting unit testing if you’ve never tried before, or if you’ve tried and given up. The Microsoft team has made unit testing incredibly easy by separating the key classes from the underlying technology, which means you can create mock implementation of key features and test corner-case situations that would be incredibly difficult to replicate otherwise. We’ll show you examples of unit testing MVC applications throughout this book. We encourage you to follow along and try unit testing for yourself.
Understanding Integration Testing
For web applications, the most common approach to integration testing is UI automation. This term refers to simulating or automating a web browser to exercise the application’s entire technology stack by reproducing the actions that a user would perform, such as clicking buttons, following links, and submitting forms.
The following are the two best-known open source browser automation options for .NET developers:
Selenium RC (http://seleniumhq.org/), which consists of a Java “server” application that can send automation commands to Internet Explorer, Firefox, Safari, or Opera, plus clients for .NET, Python, Ruby, and multiple others so that you can write test scripts in the language of your choice. Selenium is powerful and mature; its only drawback is that you have to run its Java server.
WatiN (http://watin.sourceforge.net/), a .NET library that can send automation commands to Internet Explorer or Firefox. Its API isn’t as powerful as Selenium, but it comfortably handles most common scenarios and is easy to set up (you need to reference only a single dynamic-link library).
Integration testing is an ideal complement to unit testing. While unit testing is well suited to validating the behavior of individual components at the server, integration testing lets you create tests that are client-focused, re- creating the actions of a user. As a result, it can highlight problems that come from the interaction between
components—hence the term integration testing. And since integration testing for a web application is done through the browser, you can test that JavaScript behaviors work the way they are supposed to, which is very difficult with unit testing.
There are some drawbacks, too. Integration testing takes more time. It takes longer to create the tests and longer to perform them. And integration tests can be brittle. If you change the ID attribute of a component that is checked in a test, the test will fail.
As a consequence of the additional time and effort required, integration testing is often done at key project milestones—perhaps after a weekly source code check-in, or when major functional blocks are completed.
Integration testing is every bit as useful as unit testing, and it can highlight problems that unit testing can’t. The time required to set up and run integration testing is worthwhile, and we encourage you to add it to your development process.
We aren’t going to get into integration testing in this book. That’s not because we don’t think it is useful—it is, which is why we urged you to add it to your process—but because it goes beyond the focus of this book. The ASP.NET MVC Framework has been specifically designed to make unit testing easy and simple, and we need to include unit testing to give you the full flavor of how to build a good MVC application. Integration testing is a separate art, and what is true when performing integration testing on any web application is also true for MVC.
Summary
In this chapter, we introduced you to the MVC architectural pattern and compared it to some other patterns you may have seen or heard of before. We discussed the significance of the domain model and created a simple example. We also introduced DI, which allows us to decouple components to enforce a strict separation between the parts of our application.
We demonstrated some simple unit tests, and you saw how decoupled components and DI make unit testing simple and easy. Along the way, we demonstrated our enthusiasm for TDD and showed how we write the unit tests before we write our application code. Finally, we touched upon integration testing and compared it to unit testing.
n n n
Essential Language Features
C# is a feature-rich language, and not all programmers are familiar with all of the features we will rely on in this book. In this chapter, we are going to look at the C# language features that a good MVC programmer needs to know.
We provide only a short summary of each feature. If you want more in-depth coverage of C# or LINQ, two of Adam’s books may be of interest. For a complete guide to C#, try Introducing Visual C# 2010; and for in-depth coverage of LINQ, check out Pro LINQ in C# 2010 (written with Joe Rattz); both books are published by Apress.
If you are an experienced C# programmer, you can skip the first part of this chapter. But you won’t want to miss the second part, in which we provide a tour of Razor, the new view engine introduced with MVC 3. The syntax for Razor is different from the default ASPX engine that previous versions of MVC have relied on and which is still used in ASP.NET Web Forms. Razor coexists alongside the ASPX engine, which can still be used for MVC 3 projects, but we have adopted Razor throughout this book. Even if you want to use the old <% and %> markup in your own projects, reading the Razor section in this chapter will help you follow the examples we present in this book.
Essential C# Features
We are going to start by looking at some C# language features that you’ll need to understand in order to fully follow the examples presented in the rest of the book. You don’t need to re-create the examples in this part of the chapter to be able to follow along, but if you do want to, use the Visual Studio Console Application project template; this allows you to use the System.Console class to write output to a command window.
Using Automatically Implemented Properties
The C# property feature lets you expose a piece of data from a class in a way that decouples the data from how it is set and retrieved. Listing 5-1 contains a simple example in a class called Product.
1. Listing 5-1. Defining a Property public class Product {
private string name;
public string Name { get { return name; } set { name = value; } }
}
The property, called Name, is shown in bold. The statements in the get code block (known as the getter) are performed when the value of the property is read, and the statements in the set code block are performed when a value is assigned to the property (the special variable value represents the assigned value). A property is consumed by other classes as though it were a field, as shown in Listing 5-2.
2. Listing 5-2. Consuming a Property using System;
class Program {
static void Main(string[] args) { // create a new Product object Product myProduct = new Product();
// set the property value myProduct.Name = "Kayak";
// get the property
string productName = myProduct.Name;
Console.WriteLine("Product name: {0}", productName);
} }
You can see that the property value is read and set just like a regular field. Using properties is preferable to using fields because you can change the statements in the get and set blocks without needing to change all the classes that depend on the property. All well and good, except that it gets tedious when you have a class that has a lot of properties, and all the getters and setters do the same thing—mediate access to a field. We end up with something that is needlessly verbose, as shown in Listing 5-3.
3. Listing 5-3. Verbose Property Definitions public class Product {
private int productID;
private string name;
private string description;
private decimal price;
private string category;
public int ProductID { get { return productID; } set { productID = value; } }
public string Name { get { return name; }
}
public string Description { get { return description; } set { description = value; } }
...and so on...
}
We want the flexibility of properties, but we don’t need custom getters and setters at the moment. The solution is an automatically implemented property, also known as an automatic property. With an automatic property, you can create the pattern of a field-backed property, without defining the field or specifying the code in the getter and setter, as Listing 5-4 shows.
4. Listing 5-4. Using Automatically Implemented Properties public class Product {
public int ProductID { get; set; } public string Name { get; set;}
public string Description { get; set;}
public decimal Price { get; set; } public string Category { set; get;}
}
There are a couple of key points to note when using automatic properties. The first is that we don’t define the bodies of the getter and setter. The second is that we don’t define the field that the property is backed by. Both of these are done for us by the C# compiler when we build our class. Using an automatic property is no different from using a regular property; the code in Listing 5-2 will still work. By using automatic properties, we save ourselves some typing, create code that is easier to read, and still preserve the flexibility that a property provides. If the day comes when we need to change the way a property is implemented, we can then return to the regular property format.
Let’s imagine we need to change the way the Name property is composed, as shown in Listing 5-5.
5. Listing 5-5. Reverting from an Automatic to a Regular Property public class Product {
private string name;
public int ProductID { get; set; } public string Name {
get { return ProductID + name;}
set { name = value; } }
public string Description { get; set;}
public decimal Price { get; set; }
public string Category { set; get;}
}
Note Notice that we must implement both the getter and setter to return to a regular property. C# doesn’t support mixing automatic- and regular-style getters and setters.
Using Object and Collection Initializers
Another tiresome programming task is constructing a new object and then assigning values to the properties, as shown in Listing 5-6.
6. Listing 5-6. Constructing and Initializing an Object with Properties using System;
class Program {
static void Main(string[] args) { // create a new Product object Product myProduct = new Product();
// set the property values myProduct.ProductID = 100;
myProduct.Name = "Kayak";
myProduct.Description = "A boat for one person";
myProduct.Price = 275M;
myProduct.Category = "Watersports";
// process the product ProcessProduct(myProduct);
}
private static void ProcessProduct(Product prodParam) { //...statements to process product in some way }
}
We must go through three stages to create a Product object and pass it to the ProcessProduct method: create the object, set the parameter values, and then call the method. Fortunately, we can use the object initializer feature, which allows us to do everything in one go, as shown in Listing 5-7.
7. Listing 5-7. Using the Object Initializer Feature class Program {
static void Main(string[] args) { // create a new Product object ProcessProduct(new Product { ProductID = 100, Name = "Kayak", Description = "A boat for one person", Price = 275M, Category = "Watersports"
});
}
private static void ProcessProduct(Product prodParam) { //...statements to process product in some way }
}
The braces ({}) after the call to the Product constructor are the initializer. We can supply values to the
parameters as part of the construction process. The result is an instance of the Product class that we can pass directly to the ProcessProduct method, which means we don’t need to use a local variable to refer to the Product while we initialize it. The same feature lets us initialize the contents of collections and arrays as part of the construction process, as demonstrated by Listing 5-8.
8. Listing 5-8. Initializing Collections and Arrays using System.Collections.Generic;
class Program {
static void Main(string[] args) {
string[] stringArray = { "apple", "orange", "plum" };
List<int> intList = new List<int> { 10, 20, 30, 40 };
Dictionary<string, int> myDict = new Dictionary<string, int> { { "apple", 10 },
{ "orange", 20 }, { "plum", 30 } };
} }
Listing 5-8 demonstrates how to construct and initialize an array and two classes from the generic collection library. This feature is a syntax convenience—it just makes C# more pleasant to use and doesn’t have any other impact or benefit.
Using Extension Methods
Extension methods are a convenient way of adding methods to classes that you don’t own and so can’t modify directly. Listing 5-9 shows the ShoppingCart class, which represents a collection of Products.
9. Listing 5-9. The ShoppingCart Class using System.Collections.Generic;
public class ShoppingCart {
public List<Product> Products { get; set; } }
This is a very simple class that acts as a wrapper around a List of Product objects (we only need a basic class for this example). Suppose we need to be able to determine the total value of the Product objects in the ShoppingCart class, but we can’t modify the class itself, perhaps because it comes from a third party and we don’t have the source code. Fortunately, we can use an extension method to get the functionality we need, as shown in Listing 5-10.
10. Listing 5-10. Defining an Extension Method public static class MyExtensionMethods {
public static decimal TotalPrices(this ShoppingCart cartParam) { decimal total = 0;
foreach (Product prod in cartParam.Products) { total += prod.Price;
}
return total;
} }
The this keyword in front of the first parameter marks TotalPrices as an extension method. The first parameter tells .NET which class the extension method can be applied to—ShoppingCart in our case. We can refer to the instance of the ShoppingCart that the extension method has been applied to by using the cartParam parameter. Our method enumerates through the Products in the ShoppingCart and returns the sum of the Product.Price property.
Listing 5-11 shows how we apply an extension method.
Note Extension methods don’t let you break through the access rules that classes define for their
methods, fields, and properties. You can extend the functionality of a class by using an extension method, but using only the class members that you had access to anyway.
11. Listing 5-11. Applying an Extension Method using System;
using System.Collections.Generic;
class Program {
static void Main(string[] args) { // create and populate ShoppingCart ShoppingCart cart = new ShoppingCart { Products = new List<Product> {
new Product {Name = "Kayak", Price = 275M}, new Product {Name = "Lifejacket", Price = 48.95M}, new Product {Name = "Soccer ball", Price = 19.50M}, new Product {Name = "Corner flag", Price = 34.95M}
} };
// get the total value of the products in the cart decimal cartTotal = cart.TotalPrices();
Console.WriteLine("Total: {0:c}", cartTotal);
} }
Listing 5-11 creates a ShoppingCart and populates it with Product objects using the object initializer feature.
The statement that applies the extension method is shown in bold. As you can see, we just call the method as though it were a part of the ShoppingCart class. Notice also that the extension method wasn’t defined in the same class in which we used it. .NET will find your extension classes if they are in the scope of the current class, meaning that they are part of the same namespace or in a namespace that is the subject of a using statement. Here’s the output from the class in Listing 5-11:
Total: $378.40
Applying Extension Methods to an Interface
We can also create extension methods that apply to an interface, which allows us to call the extension method on all of the classes that implement the interface. Listing 5-12 shows the ShoppingCart class updated to implement the IEnumerable<Product> interface.
12. Listing 5-12. Implementing an Interface in the ShoppingCart Class using System.Collections;
using System.Collections.Generic;
public class ShoppingCart : IEnumerable<Product> { public List<Product> Products { get; set; } public IEnumerator<Product> GetEnumerator() { return Products.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator();
} }
We can now update our extension method so that it deals with IEnumerable<Product>, as shown in Listing 5-13.
13. Listing 5-13. An Extension Method That Works on an Interface using System.Collections.Generic;
public static class MyExtensionMethods {
public static decimal TotalPrices(this IEnumerable<Product> productEnum) { decimal total = 0;
foreach (Product prod in productEnum) { total += prod.Price;
}
return total;
} }
The first parameter type has changed to IEnumerable<Product>, which means that the foreach loop in the method body works directly on the parameter object. Otherwise, the extension method is unchanged. The switch to the interface means that we can calculate the total value of the Products enumerated by any IEnumerable<Product>, which includes instances of ShoppingCart but also arrays of Products, as shown in Listing 5-14.
14. Listing 5-14. Applying an Extension Method to Different Implementations of the Same Interface using System;
using System.Collections.Generic;
class Program {
static void Main(string[] args) { // create and populate ShoppingCart
IEnumerable<Product> products = new ShoppingCart { Products = new List<Product> {
new Product {Name = "Kayak", Price = 275M}, new Product {Name = "Lifejacket", Price = 48.95M}, new Product {Name = "Soccer ball", Price = 19.50M}, new Product {Name = "Corner flag", Price = 34.95M}
} };
// create and populate an array of Product objects Product[] productArray = {
new Product {Name = "Kayak", Price = 275M},
new Product {Name = "Soccer ball", Price = 19.50M}, new Product {Name = "Corner flag", Price = 34.95M}
};
// get the total value of the products in the cart decimal cartTotal = products.TotalPrices();
decimal arrayTotal = products.TotalPrices();
Console.WriteLine("Cart Total: {0:c}", cartTotal);
Console.WriteLine("Array Total: {0:c}", arrayTotal);
} }
Note The way that C# arrays implement the IEnumerable<T> interface is a little odd. You won’t find it included in the list of implemented interfaces in the MSDN documentation. The support is handled by the compiler so that code for earlier versions C# will still compile. Odd, but true. We could have used another generic collection class in this example, but we wanted to show off our knowledge of the dark corners of the C# specification. Also odd, but true.
If you compile and run the class in Listing 5-14, you will see the following results, which demonstrate that we get the same result from the extension method, irrespective of how the Product objects are collected:
Cart Total: $378.40 Array Total: $378.40
Creating Filtering Extension Methods
The last thing we want to show you about extension methods is that they can be used to filter collections of objects.
An extension method that operates on an IEnumerable<T> and that also returns an IEnumerable<T> can use the yield keyword to apply selection criteria to items in the source data to produce a reduced set of results. Listing 5-15 demonstrates such a method.
15. Listing 5-15. A Filtering Extension Method public static IEnumerable<Product> FilterByCategory(
this IEnumerable<Product> productEnum, string categoryParam) { foreach (Product prod in productEnum) {
if (prod.Category == categoryParam) { yield return prod;