ASP.NET MVC SportStore 购物网示例(3)
测试驱动开发(TDD)
下载工具
为Tests项目添加如下引用:
nunit.Framework
System.Web
System.Web.Abstractions
System.Web.Routing
System.Web.Mvc
Moq.Dll
DomainModel
WebUI
为Tests创建类
[TestFixture]
public class ProductsControllerTests
{
[Test]
public void List_Presents_Correct_Page_Of_Products()
{
IProductsRepository repository = MockProductsRepository(
new Product { Name = "P1" }, new Product { Name = "P2" },
new Product { Name = "P3" }, new Product { Name = "P4" },
new Product { Name = "P5" }
);
ProductsController controller = new ProductsController(repository);
controller.PageSize = 3;
var result = controller.List(2);
Assert.IsNotNull(result, "Didn't render view");
var products = result.ViewData.Model as IList<Product>;
Assert.AreEqual(2, products.Count, "Got wrong number of products");
Assert.AreEqual("P4", products[0].Name);
Assert.AreEqual("P5", products[1].Name);
}
static IProductsRepository MockProductsRepository(params Product[] prods)
{
var mockProductsRepos = new Moq.Mock<IProductsRepository>();
mockProductsRepos.Setup(x => x.Products).Returns(prods.AsQueryable());
return mockProductsRepos.Object;
}
}
试着去编译代码,存在错误,因为 PageSize 和 List(2)都不存在。
为ProductController类添加 PageSize和带参数的List。
public int PageSize;
public ViewResult List(int page)
编译Tests项目。打开NUnit 载入生成的 Test.dll 文件,运行测试。
测试结果失败。
修改ProductsController类
public int PageSize = 4;
public ViewResult List(int page)
{
return View(productsRepository.Products
.Skip((page-1)*PageSize)
.Take(PageSize)
.ToList()
);
}
测试显示绿色,通过。
配置自定义的URL
为List()添加参数后,测试可能通过但运行我们实际的程序会出现错误。
添加自己的路由表
打开 Global.asax.cs改变代码如下:
routes.MapRoute(
null, // Route name
"", // URL with parameters
new { controller = "Products", action = "List", page = "1" } // Parameter defaults
);
routes.MapRoute(
null,
"Page{page}", //URL pattern, e.g. ~/Page377
new { controller = "Products", action = "List" },
new { Page = @"\d+" } //Constraints: page must be numerical
);
添加了两个URL映射:
一个空的URL, 通过 http://myweb/ 访问,为List传递了默认的参数 page=1。返回第一页数据。
Page{page}, http://myweb/Page123, 使用正则表达式 "\d+"来访问指定页的数据。
显示分页列表
创建测试类 PagingHelperTests
namespace Tests
{
using WebUI.HtmlHelpers; // The extension method will live in this namespace
[TestFixture]
public class PagingHelperTests
{
[Test]
public void PageLinks_Method_Extends_HtmlHelper()
{
HtmlHelper html = null;
html.PageLinks(0, 0, null);
}
[Test]
public void PageLinks_Producs_Anchor_Tags()
{
//第一个参数是当前页的索引
//第二个参数是每页的数量
//第三个参数是lambda方法,将一个页数映射到它的url
string links =((HtmlHelper)null).PageLinks(2,3 ,i=> "Page" + i);
Assert.AreEqual(@"<a href=""Page1"">1</a><a class=""selected"" href=""Page2"">2</a><a href=""Page3"">3</a>",links);
}
}
}
在WebUI里添加类
namespace WebUI.HtmlHelpers
{
public static class PagingHelpers
{
public static string PageLinks(this HtmlHelper html, int currentPage, int totalPages, Func<int, string> pageUrl)
{
StringBuilder result = new StringBuilder();
for (int i = 1; i <= totalPages; i++)
{
TagBuilder tag = new TagBuilder("a"); //create <a>
tag.MergeAttribute("href", pageUrl(i)); // <a href="page3" />
tag.InnerHtml = i.ToString(); //<a href="page3">3</a>
if (i == currentPage)
tag.AddCssClass("selected"); //<a href="page3" class="selected">3</a>
result.Append(tag.ToString());
}
return result.ToString();
}
}
}
测试Tests.dll看是否通过。注意 使用result.Append和result.AppendLine的区别。后者会添加 "\r\n" 格式标记。
为List.aspx添加引用
<%@ Import Namespace="WebUI.HtmlHelpers" %>
如果要为所有页都使用这个命名空间,在web.config中找到 system.web/pages添加如下代码:
<namespaces>
<add namespace="System.Web.Mvc"/>
<add namespace="System.Web.Mvc.Ajax"/>
<add namespace="WebUI.HtmlHelpers"/>
。。。。
</namespaces>
</pages>
如下代码
<%=Html.PageLinks(2,3,i=>Url.Action("List",new {page=i})) %>
将生成:
<a href="/Page1">1</a>
<a class="selected" href="/Page2">2</a>
<a href="/Page3">3</a>
为视图提供一个页数
在ProductsControllerTests.cs的 List_Presents_Correct_Page_Of_Products()中添加如下测试代码:
Assert.AreEqual(2, products.Count, "Got wrong number of products");
Assert.AreEqual(2, (int)result.ViewData["CurrentPage"], "Wrong page number");
Assert.AreEqual(2, (int)result.ViewData["TotalPages"], "Wrong page count");
Assert.AreEqual("P4", products[0].Name);
Assert.AreEqual("P5", products[1].Name);
使用ViewData来存储当前页码和总页数,为ProductsController的List()方法添加代码:
public ViewResult List(int page)
{
int numProducts = productsRepository.Products.Count();
ViewData["TotalPages"] = (int)Math.Ceiling((double)numProducts / PageSize);
ViewData["CurrentPage"] = page;
return View(productsRepository.Products
.Skip((page-1)*PageSize)
.Take(PageSize)
.ToList()
);
}
运行测试,看是否通过。
最后在List.aspx中添加分页代码:
<%=Html.PageLinks((int)ViewData["CurrentPage"],(int)ViewData["TotalPages"],i=>Url.Action("List",new {page=i})) %>
F5 运行。